pub struct AppError { /* private fields */ }Expand description
Application-level structured error.
Carries a machine-readable ErrorCode, a human-readable message,
optional key→value details for rich error responses,
and an optional cause chain compatible with std::error::Error.
Fields are private to preserve the error’s invariants. http_status is fully determined by code
and can never drift from it. retryable is seeded from code’s default
but may be intentionally overridden via the AppError::retryable builder;
read access is via the getter methods
and mutation via the builder methods (with_*, retryable, context).
details deliberately uses serde_json::Value:
it models RFC 9457 problem-detail extension members, which are by definition arbitrary JSON
and cannot be given a closed type without losing that openness.
Implementations§
Source§impl AppError
impl AppError
Sourcepub fn new(code: ErrorCode, message: impl Into<String>) -> AppError
pub fn new(code: ErrorCode, message: impl Into<String>) -> AppError
Create a new AppError from code and a human-readable message.
Sourcepub fn with_cause(self, cause: impl Error + Send + Sync + 'static) -> AppError
pub fn with_cause(self, cause: impl Error + Send + Sync + 'static) -> AppError
Attach an underlying cause to this error.
Sourcepub fn with_detail(
self,
key: impl Into<String>,
value: impl Into<Value>,
) -> AppError
pub fn with_detail( self, key: impl Into<String>, value: impl Into<Value>, ) -> AppError
Add a single key-value detail entry.
Sourcepub fn with_details(self, details: HashMap<String, Value>) -> AppError
pub fn with_details(self, details: HashMap<String, Value>) -> AppError
Merge a map of detail entries into this error.
Sourcepub fn retryable(self, r: bool) -> AppError
pub fn retryable(self, r: bool) -> AppError
Override whether this error is considered retryable.
Create a ServiceUnavailable error for the named service.
Sourcepub fn connection_failed(service: impl Into<String>) -> AppError
pub fn connection_failed(service: impl Into<String>) -> AppError
Create a ConnectionFailed error for the named service.
Sourcepub fn timeout(operation: impl Into<String>) -> AppError
pub fn timeout(operation: impl Into<String>) -> AppError
Create a Timeout error for the named operation.
Sourcepub fn rate_limited() -> AppError
pub fn rate_limited() -> AppError
Create a RateLimited error.
Sourcepub fn not_found(resource: impl Into<String>, id: Option<&str>) -> AppError
pub fn not_found(resource: impl Into<String>, id: Option<&str>) -> AppError
Create a NotFound error for resource, optionally including an id.
Sourcepub fn already_exists(resource: impl Into<String>) -> AppError
pub fn already_exists(resource: impl Into<String>) -> AppError
Create an AlreadyExists error for the named resource.
Sourcepub fn conflict(reason: impl Into<String>) -> AppError
pub fn conflict(reason: impl Into<String>) -> AppError
Create a Conflict error with the given reason.
Sourcepub fn invalid_input(
field: impl Into<String>,
reason: impl Into<String>,
) -> AppError
pub fn invalid_input( field: impl Into<String>, reason: impl Into<String>, ) -> AppError
Create an InvalidInput error for the named field.
Sourcepub fn missing_field(field: impl Into<String>) -> AppError
pub fn missing_field(field: impl Into<String>) -> AppError
Create a MissingField error for the named required field.
Sourcepub fn invalid_format(
field: impl Into<String>,
expected: impl Into<String>,
) -> AppError
pub fn invalid_format( field: impl Into<String>, expected: impl Into<String>, ) -> AppError
Create an InvalidFormat error for the named field.
Create an Unauthorized error with the given reason.
Sourcepub fn forbidden(reason: impl Into<String>) -> AppError
pub fn forbidden(reason: impl Into<String>) -> AppError
Create a Forbidden error with the given reason.
Sourcepub fn token_expired() -> AppError
pub fn token_expired() -> AppError
Create a TokenExpired error.
Sourcepub fn invalid_token() -> AppError
pub fn invalid_token() -> AppError
Create an InvalidToken error.
Sourcepub fn internal(cause: impl Error + Send + Sync + 'static) -> AppError
pub fn internal(cause: impl Error + Send + Sync + 'static) -> AppError
Wrap an arbitrary error as an Internal application error.
The cause is stored internally for logging but is NOT included in the serialized response — callers receive a generic “internal server error” message.
Sourcepub fn database_error(cause: impl Error + Send + Sync + 'static) -> AppError
pub fn database_error(cause: impl Error + Send + Sync + 'static) -> AppError
Wrap a database error.
The cause is stored internally for logging but is NOT included in the serialized response — callers receive a generic “database error” message.
Sourcepub fn external_service(
service: impl Into<String>,
cause: impl Error + Send + Sync + 'static,
) -> AppError
pub fn external_service( service: impl Into<String>, cause: impl Error + Send + Sync + 'static, ) -> AppError
Wrap an external service error, naming the dependency.
The cause is stored internally for logging but is NOT included in the serialized response — callers receive a generic message naming only the service.
Sourcepub fn cancelled(operation: impl Into<String>) -> AppError
pub fn cancelled(operation: impl Into<String>) -> AppError
Create a Cancelled error for the named operation.
Sourcepub fn context(self, msg: impl Into<String>) -> AppError
pub fn context(self, msg: impl Into<String>) -> AppError
Add human-readable context to this error.
Prepends msg to the existing error message so call-site context is preserved in logs
and error responses without losing the original cause.
§Examples
let err = AppError::new(ErrorCode::NotFound, "user not found")
.context("load profile");
assert_eq!(err.message(), "load profile: user not found");Sourcepub fn hint(self, hint: impl Into<String>) -> AppError
pub fn hint(self, hint: impl Into<String>) -> AppError
Append a trailing hint after the existing error message.
The counterpart to context: where context prepends call-site context,
hint appends advisory guidance (for example a “did you mean …?” suggestion) as a new sentence,
preserving the code, cause, structured details, and retryability of the original error.
An empty or whitespace-only hint is a no-op, so an optional
or derived suggestion can be threaded through without a conditional at the call site.
The hint is trimmed of surrounding whitespace
and appended onto the existing message (separated by a single space when the message is non-empty);
the caller supplies any punctuation within the hint itself.
§Examples
let err = AppError::invalid_input("task", "no such task 'buld'")
.hint("Did you mean 'build'?");
assert_eq!(
err.message(),
"invalid task: no such task 'buld' Did you mean 'build'?"
);Sourcepub fn is_retryable(&self) -> bool
pub fn is_retryable(&self) -> bool
Returns true if the operation that produced this error is safe to retry.
Sourcepub fn is_not_found(&self) -> bool
pub fn is_not_found(&self) -> bool
Returns true if this error indicates a missing resource.
Returns true if this error is an authentication/authorisation failure.
Sourcepub const fn http_status(&self) -> StatusCode
pub const fn http_status(&self) -> StatusCode
Canonical HTTP status code for this error.
Trait Implementations§
Source§impl Error for AppError
impl Error for AppError
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
use the Display impl or to_string()
Source§impl From<InferenceError> for AppError
impl From<InferenceError> for AppError
Source§fn from(value: InferenceError) -> AppError
fn from(value: InferenceError) -> AppError
Source§impl From<SkillError> for AppError
impl From<SkillError> for AppError
Source§fn from(value: SkillError) -> AppError
fn from(value: SkillError) -> AppError
Source§impl Serialize for AppError
impl Serialize for AppError
Source§fn serialize<S>(
&self,
ser: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>(
&self,
ser: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
Auto Trait Implementations§
impl !RefUnwindSafe for AppError
impl !UnwindSafe for AppError
impl Freeze for AppError
impl Send for AppError
impl Sync for AppError
impl Unpin for AppError
impl UnsafeUnpin for AppError
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request