symfonic.platform.errors¶
errors ¶
The platform taxonomy: one class per refusal, each with a stable code.
EMAP-2 forbids mapping on message text, so every class here carries the machine
-readable code a transport keys on. The four refusals a derivation can
produce are separate classes rather than one error with a field, because
T3.4.5 asserts three distinct refusals on the resume path precisely so a
transport can map them without parsing prose โ and a taxonomy that collapses
them again would undo that at the layer above.
AuthenticationError ¶
Bases: PlatformError
No derivable credentials. 401.
Never a fallback to a default, shared, or root tenant (SCOPE-4, SEC-FCP-1).
AuthorizationError ¶
Bases: PlatformError
Authenticated, but not for this scope. 403.
Also raised by :meth:AuthenticatedPrincipal.narrowed on an attempted
widening and by require_self on a redirect attempt (SCOPE-8/SEC-AUTHZ-2),
because "you may not act on that tenant" is one answer however it was asked.
BudgetExceededError ¶
BudgetExceededError(message: str, *, code: str = 'budget_exceeded', reason: str | None = None, retry_after: int = 3600, scope_key: str = '')
Bases: PlatformError
Admission refused by the budget port. 429 + Retry-After.
This class is BUD-2's whole point. The shipped path raises a generic error
whose message starts "Budget exceeded:" and three routers branch on that
prefix; here the class carries the decision, code distinguishes
exhaustion from an unavailable ledger, and retry_after is a number
rather than a hard-coded header string in three places.
Source code in src/symfonic/platform/errors.py
DestructiveConfirmationError ¶
Bases: PlatformError
A destructive operation arrived without intent bound to the resolved scope.
ADM-5: the confirmation is compared against the derived tenant id, never against a value taken from the same request that supplied the confirmation โ otherwise the check confirms only that the caller can copy a string.