pub enum AppError {
Show 23 variants
Config(String),
Io(Error),
Store(Error),
Serialization(Error),
Internal(String),
SecretStore(String),
NotFound(String),
Conflict(String),
Secrets(SecretsResolverError),
Authentication(String),
Unauthorized(String),
Forbidden(String),
StepUpRequired(String),
ApprovalRequired {
code: &'static str,
details: Value,
},
Validation(String),
TrustTaskMissing,
TrustTaskMismatch {
expected: String,
received: Option<String>,
},
TrustTaskMalformed(String),
IdempotencyKeyConflict,
InvalidCursor,
ResourceExhausted(String),
ServiceError {
status: StatusCode,
message: String,
},
Vsock {
operation: &'static str,
source: Error,
},
}Variants§
Config(String)
Io(Error)
Store(Error)
Serialization(Error)
Internal(String)
SecretStore(String)
NotFound(String)
Conflict(String)
Secrets(SecretsResolverError)
Authentication(String)
Forbidden(String)
StepUpRequired(String)
Operation requires a stepped-up (acr=aal2) session, but
the caller’s JWT carries a lower acr (typically aal1).
Distinct from Self::Forbidden so wallets can react —
step_up_required is the operator-friendly signal to
trigger a passkey-login or VTA-approval ceremony, not a
hard rejection.
Rendered as 403 Forbidden with body
{ "error": "step_up_required", "message": "...", "requiredAcr": "aal2" } so clients can distinguish it
from a role-based rejection without parsing English.
ApprovalRequired
The Policy Decision Point refused the request until an approval is obtained, and is handing back what obtaining it requires.
Distinct from Self::StepUpRequired because that variant can only say
that elevation is needed — it renders {error, message, requiredAcr}
and has nowhere to put the approveRequest the caller must get signed,
nor any way to express a consent requirement (approver set, threshold,
challenge). A REST caller receiving it could learn it was blocked but
not what to do about it, while the trust-task caller for the very same
decision received the full document. That asymmetry is what this closes.
code is the stable machine-readable reason (auth:step_up_required,
auth:consent_required) — the field a client keys on, rather than the
HTTP status or the English message. details is merged into the body,
so the REST response carries exactly what the trust-task reject’s
details carries.
Rendered as 403 Forbidden: the request was understood and the caller authenticated; it is refused pending a decision they can still obtain.
Validation(String)
TrustTaskMissing
The request did not carry a required Trust-Task header. Routes
registered via crate::trust_task::TrustTaskRouter::route_with_task
reject missing headers with this variant (400). Only /health is
allowed to omit it.
TrustTaskMismatch
The request’s Trust-Task header did not match the handler’s
registered task. Returned as 415 per spec §16.2; the response body
carries the expected + received task URLs so clients can diagnose
without re-reading the route table.
TrustTaskMalformed(String)
The supplied Trust-Task value was not a well-formed identifier
(empty, non-https://, or contained header-injection control
characters). Returned as 400.
IdempotencyKeyConflict
A request reused an Idempotency-Key it had previously sent
with a different body hash. The cached response is preserved
for the original requester; the conflicting retry is rejected
with 422 so clients don’t silently get a stale response from a
drifting payload.
InvalidCursor
A pagination cursor failed integrity verification — either the HMAC tag didn’t validate (tampered, forged, or signed under a different community’s audit_key) or the encoded form was malformed. Returned as 400 with no extra detail so an attacker can’t learn whether their guessed cursor was structurally close to a valid one.
ResourceExhausted(String)
A bounded computation aborted because it hit a resource ceiling (time/instruction budget or an input-size cap) before completing. Used by the Rego policy evaluator to refuse pathological policies or adversarial inputs on the unauthenticated join path rather than burning CPU unbounded. Rendered as 503 Service Unavailable — the evaluation did not complete, and the message is generic so an attacker can’t probe the exact limits.
ServiceError
Catch-all for service-specific errors (e.g., KeyDerivation, BadGateway, TeeAttestation). Services create helper functions to construct these with appropriate status codes.
Vsock
An I/O failure in a vsock operation. Preserves the underlying
std::io::Error via #[source] while adding a human-readable
label of which operation failed (connect / read / write / flush).
Construct via AppError::vsock for ergonomic .map_err(...).
Implementations§
Source§impl AppError
impl AppError
Sourcepub fn vsock(operation: &'static str) -> impl FnOnce(Error) -> AppError
pub fn vsock(operation: &'static str) -> impl FnOnce(Error) -> AppError
Build a closure suitable for .map_err(...) that wraps an
std::io::Error into AppError::Vsock with the given operation
label. Keeps the source chain intact for downstream error walkers
while giving log readers the operation name.
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<AuthError> for AppError
Convert the canonical auth-flow errors into AppError so
the route layer’s existing IntoResponse plumbing renders
them without backend-specific glue. Each variant lands on the
HTTP status reflected in the crate::auth::AuthError
doc-comments:
impl From<AuthError> for AppError
Convert the canonical auth-flow errors into AppError so
the route layer’s existing IntoResponse plumbing renders
them without backend-specific glue. Each variant lands on the
HTTP status reflected in the crate::auth::AuthError
doc-comments:
Forbidden,DidMethodRejected→ 403PendingChallengeLimitReached→ 429 via the Validation arm (route layer can return a typed 429 if needed; the canonical variant carries the rate-limit signal in the message).SessionNotFound,SessionStateMismatch,ChallengeMismatch,ChallengeExpired,SignerMismatch,StaleMessage,RefreshTokenInvalid,RefreshTokenExpired→ 401AttestationFailed→ 503 via Internal (TEE outages are not the caller’s fault).Internal→ 500.