pub struct AppError { /* private fields */ }Expand description
Rich application error preserving domain code, taxonomy and metadata.
This is the main error type for application-level errors. It provides structured error information, telemetry integration, and diagnostic capabilities.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::BadRequest, "invalid payload");
assert_eq!(err.kind, AppErrorKind::BadRequest);Implementations§
Source§impl Error
impl Error
Sourcepub fn not_found(msg: impl Into<Cow<'static, str>>) -> Error
pub fn not_found(msg: impl Into<Cow<'static, str>>) -> Error
Build a NotFound error.
use masterror::AppError;
let err = AppError::not_found("user not found");
assert_eq!(err.message.as_deref(), Some("user not found"));Sourcepub fn validation(msg: impl Into<Cow<'static, str>>) -> Error
pub fn validation(msg: impl Into<Cow<'static, str>>) -> Error
Build a Validation error.
use masterror::AppError;
let err = AppError::validation("invalid email format");
assert_eq!(err.message.as_deref(), Some("invalid email format"));Build an Unauthorized error.
use masterror::AppError;
let err = AppError::unauthorized("missing authentication token");
assert_eq!(err.message.as_deref(), Some("missing authentication token"));Sourcepub fn forbidden(msg: impl Into<Cow<'static, str>>) -> Error
pub fn forbidden(msg: impl Into<Cow<'static, str>>) -> Error
Build a Forbidden error.
use masterror::AppError;
let err = AppError::forbidden("insufficient permissions");
assert_eq!(err.message.as_deref(), Some("insufficient permissions"));Sourcepub fn conflict(msg: impl Into<Cow<'static, str>>) -> Error
pub fn conflict(msg: impl Into<Cow<'static, str>>) -> Error
Build a Conflict error.
use masterror::AppError;
let err = AppError::conflict("resource already exists");
assert_eq!(err.message.as_deref(), Some("resource already exists"));Sourcepub fn bad_request(msg: impl Into<Cow<'static, str>>) -> Error
pub fn bad_request(msg: impl Into<Cow<'static, str>>) -> Error
Build a BadRequest error.
use masterror::AppError;
let err = AppError::bad_request("malformed JSON payload");
assert_eq!(err.message.as_deref(), Some("malformed JSON payload"));Sourcepub fn rate_limited(msg: impl Into<Cow<'static, str>>) -> Error
pub fn rate_limited(msg: impl Into<Cow<'static, str>>) -> Error
Build a RateLimited error.
use masterror::AppError;
let err = AppError::rate_limited("rate limit exceeded");
assert_eq!(err.message.as_deref(), Some("rate limit exceeded"));Sourcepub fn telegram_auth(msg: impl Into<Cow<'static, str>>) -> Error
pub fn telegram_auth(msg: impl Into<Cow<'static, str>>) -> Error
Build a TelegramAuth error.
use masterror::AppError;
let err = AppError::telegram_auth("invalid telegram signature");
assert_eq!(err.message.as_deref(), Some("invalid telegram signature"));Sourcepub fn internal(msg: impl Into<Cow<'static, str>>) -> Error
pub fn internal(msg: impl Into<Cow<'static, str>>) -> Error
Build an Internal error.
use masterror::AppError;
let err = AppError::internal("unexpected server error");
assert_eq!(err.message.as_deref(), Some("unexpected server error"));Sourcepub fn service(msg: impl Into<Cow<'static, str>>) -> Error
pub fn service(msg: impl Into<Cow<'static, str>>) -> Error
Build a Service error (generic server-side service failure).
use masterror::AppError;
let err = AppError::service("service processing failed");
assert_eq!(err.message.as_deref(), Some("service processing failed"));Sourcepub fn database(msg: Option<Cow<'static, str>>) -> Error
pub fn database(msg: Option<Cow<'static, str>>) -> Error
Build a Database error with an optional message.
This constructor accepts a pre-built Cow so callers that already
manage ownership can pass either borrowed or owned strings. When you
have plain string data, prefer AppError::database_with_message.
use masterror::AppError;
let err = AppError::database(None);
assert!(err.message.is_none());Sourcepub fn database_with_message(msg: impl Into<Cow<'static, str>>) -> Error
pub fn database_with_message(msg: impl Into<Cow<'static, str>>) -> Error
Build a Database error with a message.
Convenience wrapper around AppError::database for the common case
where you start from a plain string-like value.
use masterror::AppError;
let err = AppError::database_with_message("db down");
assert_eq!(err.message.as_deref(), Some("db down"));Sourcepub fn config(msg: impl Into<Cow<'static, str>>) -> Error
pub fn config(msg: impl Into<Cow<'static, str>>) -> Error
Build a Config error.
use masterror::AppError;
let err = AppError::config("missing required configuration key");
assert_eq!(
err.message.as_deref(),
Some("missing required configuration key")
);Sourcepub fn turnkey(msg: impl Into<Cow<'static, str>>) -> Error
pub fn turnkey(msg: impl Into<Cow<'static, str>>) -> Error
Build a Turnkey error.
use masterror::AppError;
let err = AppError::turnkey("turnkey operation failed");
assert_eq!(err.message.as_deref(), Some("turnkey operation failed"));Sourcepub fn timeout(msg: impl Into<Cow<'static, str>>) -> Error
pub fn timeout(msg: impl Into<Cow<'static, str>>) -> Error
Build a Timeout error.
use masterror::AppError;
let err = AppError::timeout("request timed out after 30s");
assert_eq!(err.message.as_deref(), Some("request timed out after 30s"));Sourcepub fn network(msg: impl Into<Cow<'static, str>>) -> Error
pub fn network(msg: impl Into<Cow<'static, str>>) -> Error
Build a Network error.
use masterror::AppError;
let err = AppError::network("connection refused");
assert_eq!(err.message.as_deref(), Some("connection refused"));Build a DependencyUnavailable error.
use masterror::AppError;
let err = AppError::dependency_unavailable("payment service unavailable");
assert_eq!(err.message.as_deref(), Some("payment service unavailable"));Backward-compatible alias; routes to DependencyUnavailable.
use masterror::AppError;
let err = AppError::service_unavailable("service temporarily unavailable");
assert_eq!(
err.message.as_deref(),
Some("service temporarily unavailable")
);Sourcepub fn serialization(msg: impl Into<Cow<'static, str>>) -> Error
pub fn serialization(msg: impl Into<Cow<'static, str>>) -> Error
Build a Serialization error.
use masterror::AppError;
let err = AppError::serialization("failed to serialize response");
assert_eq!(err.message.as_deref(), Some("failed to serialize response"));Sourcepub fn deserialization(msg: impl Into<Cow<'static, str>>) -> Error
pub fn deserialization(msg: impl Into<Cow<'static, str>>) -> Error
Build a Deserialization error.
use masterror::AppError;
let err = AppError::deserialization("failed to parse JSON");
assert_eq!(err.message.as_deref(), Some("failed to parse JSON"));Sourcepub fn external_api(msg: impl Into<Cow<'static, str>>) -> Error
pub fn external_api(msg: impl Into<Cow<'static, str>>) -> Error
Build an ExternalApi error.
use masterror::AppError;
let err = AppError::external_api("third-party API returned error");
assert_eq!(
err.message.as_deref(),
Some("third-party API returned error")
);Source§impl Error
impl Error
Sourcepub fn new(kind: AppErrorKind, msg: impl Into<Cow<'static, str>>) -> Error
pub fn new(kind: AppErrorKind, msg: impl Into<Cow<'static, str>>) -> Error
Create a new Error with a kind and message.
This is equivalent to Error::with, provided for API symmetry and to
keep doctests readable.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::BadRequest, "invalid payload");
assert!(err.message.is_some());Sourcepub fn with(kind: AppErrorKind, msg: impl Into<Cow<'static, str>>) -> Error
pub fn with(kind: AppErrorKind, msg: impl Into<Cow<'static, str>>) -> Error
Create an error with the given kind and message.
Prefer named helpers (e.g. Error::not_found) where it clarifies
intent.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::with(AppErrorKind::Validation, "bad input");
assert_eq!(err.kind, AppErrorKind::Validation);Sourcepub fn bare(kind: AppErrorKind) -> Error
pub fn bare(kind: AppErrorKind) -> Error
Create a message-less error with the given kind.
Useful when the kind alone conveys sufficient information to the client.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::bare(AppErrorKind::NotFound);
assert!(err.message.is_none());Sourcepub fn with_retry_after_secs(self, secs: u64) -> Error
pub fn with_retry_after_secs(self, secs: u64) -> Error
Attach retry advice to the error.
When mapped to HTTP, this becomes the Retry-After header.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::RateLimited, "slow down").with_retry_after_secs(60);
assert_eq!(err.retry.map(|r| r.after_seconds), Some(60));Sourcepub fn with_www_authenticate(self, value: impl Into<String>) -> Error
pub fn with_www_authenticate(self, value: impl Into<String>) -> Error
Attach a WWW-Authenticate challenge string.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::Unauthorized, "auth required")
.with_www_authenticate("Bearer realm=\"api\"");
assert!(err.www_authenticate.is_some());Sourcepub fn with_field(self, field: Field) -> Error
pub fn with_field(self, field: Field) -> Error
Attach additional metadata to the error.
§Examples
use masterror::{AppError, AppErrorKind, field};
let err = AppError::new(AppErrorKind::Validation, "bad field")
.with_field(field::str("field_name", "email"));
assert!(err.metadata().get("field_name").is_some());Sourcepub fn with_fields(self, fields: impl IntoIterator<Item = Field>) -> Error
pub fn with_fields(self, fields: impl IntoIterator<Item = Field>) -> Error
Extend metadata from an iterator of fields.
§Examples
use masterror::{AppError, AppErrorKind, field};
let fields = vec![field::str("key1", "value1"), field::str("key2", "value2")];
let err = AppError::new(AppErrorKind::BadRequest, "test").with_fields(fields);
assert!(err.metadata().get("key1").is_some());Sourcepub fn redact_field(
self,
name: &'static str,
redaction: FieldRedaction,
) -> Error
pub fn redact_field( self, name: &'static str, redaction: FieldRedaction, ) -> Error
Override the redaction policy for a stored metadata field.
§Examples
use masterror::{AppError, AppErrorKind, FieldRedaction, field};
let err = AppError::new(AppErrorKind::Internal, "test")
.with_field(field::str("password", "secret"))
.redact_field("password", FieldRedaction::Redact);Sourcepub fn with_metadata(self, metadata: Metadata) -> Error
pub fn with_metadata(self, metadata: Metadata) -> Error
Replace metadata entirely.
§Examples
use masterror::{AppError, AppErrorKind, Metadata};
let metadata = Metadata::new();
let err = AppError::new(AppErrorKind::Internal, "test").with_metadata(metadata);Sourcepub fn redactable(self) -> Error
pub fn redactable(self) -> Error
Mark the message as redactable.
§Examples
use masterror::{AppError, AppErrorKind, MessageEditPolicy};
let err = AppError::new(AppErrorKind::Internal, "secret").redactable();
assert_eq!(err.edit_policy, MessageEditPolicy::Redact);Sourcepub fn with_context(self, context: impl Into<ContextAttachment>) -> Error
pub fn with_context(self, context: impl Into<ContextAttachment>) -> Error
Attach upstream diagnostics using with_source or
an existing Arc.
This is the preferred alias for capturing upstream errors. It accepts
either an owned error implementing core::error::Error or a
shared Arc produced by other APIs, reusing the allocation when
possible.
§Examples
use masterror::AppError;
let err = AppError::service("downstream degraded")
.with_context(std::io::Error::new(std::io::ErrorKind::Other, "boom"));
assert!(err.source_ref().is_some());Sourcepub fn with_source(self, source: impl Error + Send + Sync + 'static) -> Error
pub fn with_source(self, source: impl Error + Send + Sync + 'static) -> Error
Attach a source error for diagnostics.
Prefer with_context when capturing upstream
diagnostics without additional Arc allocations.
§Examples
use masterror::{AppError, AppErrorKind};
let io_err = std::io::Error::new(std::io::ErrorKind::Other, "boom");
let err = AppError::internal("boom").with_source(io_err);
assert!(err.source_ref().is_some());Sourcepub fn with_source_arc(self, source: Arc<dyn Error + Sync + Send>) -> Error
pub fn with_source_arc(self, source: Arc<dyn Error + Sync + Send>) -> Error
Attach a shared source error without cloning the underlying Arc.
§Examples
use std::sync::Arc;
use masterror::{AppError, AppErrorKind};
let source = Arc::new(std::io::Error::new(std::io::ErrorKind::Other, "boom"));
let err = AppError::internal("boom").with_source_arc(source.clone());
assert!(err.source_ref().is_some());
assert_eq!(Arc::strong_count(&source), 2);Sourcepub fn with_backtrace(self, backtrace: Backtrace) -> Error
pub fn with_backtrace(self, backtrace: Backtrace) -> Error
Attach a captured backtrace.
§Examples
use std::backtrace::Backtrace;
use masterror::AppError;
let bt = Backtrace::capture();
let err = AppError::internal("test").with_backtrace(bt);Sourcepub fn with_details_text(self, details: impl Into<String>) -> Error
pub fn with_details_text(self, details: impl Into<String>) -> Error
Attach plain-text details for client payloads.
The text is omitted from responses when the error is
redactable.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::Internal, "boom").with_details_text("retry later");
assert!(err.details.is_some());Source§impl Error
impl Error
Sourcepub fn metadata(&self) -> &Metadata
pub fn metadata(&self) -> &Metadata
Borrow the attached metadata.
§Examples
use masterror::{AppError, field};
let err = AppError::internal("test").with_field(field::str("key", "value"));
let metadata = err.metadata();
assert!(!metadata.is_empty());Sourcepub fn backtrace(&self) -> Option<&Backtrace>
pub fn backtrace(&self) -> Option<&Backtrace>
Borrow the backtrace, capturing it lazily when the backtrace feature
is enabled.
If a backtrace was previously attached via with_backtrace(), returns
that. Otherwise, lazily captures a new backtrace based on
RUST_BACKTRACE configuration.
§Examples
use masterror::AppError;
let err = AppError::internal("test");
let bt = err.backtrace();Sourcepub fn source_ref(&self) -> Option<&(dyn Error + Sync + Send + 'static)>
pub fn source_ref(&self) -> Option<&(dyn Error + Sync + Send + 'static)>
Borrow the source if present.
§Examples
use masterror::AppError;
let io_err = std::io::Error::new(std::io::ErrorKind::Other, "boom");
let err = AppError::internal("failed").with_context(io_err);
assert!(err.source_ref().is_some());Sourcepub fn render_message(&self) -> Cow<'_, str>
pub fn render_message(&self) -> Cow<'_, str>
Human-readable message or the kind fallback.
Returns the error message if set, otherwise returns the error kind’s default label.
§Examples
use masterror::{AppError, AppErrorKind};
let err = AppError::new(AppErrorKind::BadRequest, "custom message");
assert_eq!(err.render_message(), "custom message");
let bare_err = AppError::bare(AppErrorKind::NotFound);
assert!(!bare_err.render_message().is_empty());Sourcepub fn log(&self)
pub fn log(&self)
Emit telemetry (tracing event, metrics counter, backtrace capture).
Downstream code can call this to guarantee telemetry after mutating the error. It is automatically invoked by constructors and conversions.
§Examples
use masterror::AppError;
let err = AppError::internal("test");
err.log();Sourcepub fn chain(&self) -> ErrorChain<'_>
pub fn chain(&self) -> ErrorChain<'_>
Returns an iterator over the error chain, starting with this error.
The iterator yields references to each error in the source chain,
walking through source() until reaching the
root cause.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let app_err = AppError::internal("db down").with_context(io_err);
let chain: Vec<_> = app_err.chain().collect();
assert_eq!(chain.len(), 2);Sourcepub fn root_cause(&self) -> &(dyn Error + 'static)
pub fn root_cause(&self) -> &(dyn Error + 'static)
Returns the lowest-level source error in the chain.
This traverses the error source chain until it finds an error with no further source, then returns a reference to it. If this error has no source, it returns a reference to itself.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let app_err = AppError::internal("db down").with_context(io_err);
let root = app_err.root_cause();
assert_eq!(root.to_string(), "disk offline");Sourcepub fn is<E>(&self) -> boolwhere
E: Error + 'static,
pub fn is<E>(&self) -> boolwhere
E: Error + 'static,
Attempts to downcast the error source to a concrete type.
Returns true if the error source is of type E, false otherwise.
This only checks the immediate source, not the entire chain.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let app_err = AppError::internal("db down").with_context(io_err);
assert!(app_err.is::<IoError>());
let err_without_source = AppError::not_found("missing");
assert!(!err_without_source.is::<IoError>());Sourcepub fn downcast<E>(self) -> Result<Box<E>, Error>where
E: Error + 'static,
pub fn downcast<E>(self) -> Result<Box<E>, Error>where
E: Error + 'static,
Attempt to downcast the error source to a concrete type by value.
Note: This method is currently a stub and always returns
Err(Self).
Use downcast_ref for inspecting error sources.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let err = AppError::internal("boom").with_context(io_err);
assert!(err.downcast::<IoError>().is_err());Sourcepub fn downcast_ref<E>(&self) -> Option<&E>where
E: Error + 'static,
pub fn downcast_ref<E>(&self) -> Option<&E>where
E: Error + 'static,
Attempt to downcast the error to a concrete type by immutable reference.
Returns Some(&E) if this error is of type E, None otherwise.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let err = AppError::internal("boom").with_context(io_err);
if let Some(io) = err.downcast_ref::<IoError>() {
assert_eq!(io.to_string(), "disk offline");
}Sourcepub fn downcast_mut<E>(&mut self) -> Option<&mut E>where
E: Error + 'static,
pub fn downcast_mut<E>(&mut self) -> Option<&mut E>where
E: Error + 'static,
Attempt to downcast the error to a concrete type by mutable reference.
Returns Some(&mut E) if this error is of type E, None otherwise.
§Examples
use std::io::Error as IoError;
use masterror::AppError;
let io_err = IoError::other("disk offline");
let mut err = AppError::internal("boom").with_context(io_err);
if let Some(_io) = err.downcast_mut::<IoError>() {
// Can modify the IoError if needed
}Trait Implementations§
Source§impl Error for Error
impl Error for Error
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
Source§impl From<ConfigError> for AppError
impl From<ConfigError> for AppError
Source§fn from(value: ConfigError) -> Self
fn from(value: ConfigError) -> Self
Source§impl From<ConfigValidationError> for AppError
impl From<ConfigValidationError> for AppError
Source§fn from(value: ConfigValidationError) -> Self
fn from(value: ConfigValidationError) -> Self
Source§impl From<DiffParseError> for AppError
impl From<DiffParseError> for AppError
Source§fn from(value: DiffParseError) -> Self
fn from(value: DiffParseError) -> Self
Source§impl From<Error> for Error
Available on crate feature std only.Map std::io::Error to an internal application error.
impl From<Error> for Error
std only.Map std::io::Error to an internal application error.
Rationale: I/O failures are infrastructure-level and should not leak
driver-specific details to clients. The message is preserved for
observability, but the public-facing kind is always Internal.
use std::io::{self, ErrorKind};
use masterror::{AppError, AppErrorKind};
let io_err = io::Error::from(ErrorKind::Other);
let app_err: AppError = io_err.into();
assert!(matches!(app_err.kind, AppErrorKind::Internal));Source§impl From<FileReadError> for AppError
impl From<FileReadError> for AppError
Source§fn from(value: FileReadError) -> Self
fn from(value: FileReadError) -> Self
Source§impl From<LimitExceededError> for AppError
impl From<LimitExceededError> for AppError
Source§fn from(value: LimitExceededError) -> Self
fn from(value: LimitExceededError) -> Self
Source§impl From<OutputError> for AppError
impl From<OutputError> for AppError
Source§fn from(value: OutputError) -> Self
fn from(value: OutputError) -> Self
Source§impl From<ParseError> for AppError
impl From<ParseError> for AppError
Source§fn from(value: ParseError) -> Self
fn from(value: ParseError) -> Self
Source§impl From<String> for Error
Map a plain String to a client error (BadRequest).
impl From<String> for Error
Map a plain String to a client error (BadRequest).
Handy for quick validation paths without the validator feature.
Prefer structured validation for complex DTOs, but this covers simple cases.
use masterror::{AppError, AppErrorKind, AppResult};
fn check(name: &str) -> AppResult<()> {
if name.is_empty() {
return Err(String::from("name must not be empty").into());
}
Ok(())
}
let err = check("").unwrap_err();
assert!(matches!(err.kind, AppErrorKind::BadRequest));