Skip to content

Error Reference

Startup Configuration Errors

Settings validation rejects unknown fields and unsupported feature combinations before the server starts. Treat an unusable SQLite path, OIDC without its authorization-code/JWKS prerequisites, or interactive grants without browser sessions as deployment configuration errors.

Application dependencies raise RuntimeError only if required configuration or request state is incomplete. create_app() stores the immutable settings snapshot on the application; request dependencies own database sessions and focused service construction.

OAuth2 Protocol Errors

OAuth2 endpoints return RFC-style error names such as invalid_request, invalid_client, invalid_grant, authorization_pending, and slow_down. Clients must use the protocol error field rather than parsing human-readable descriptions. Unexpected protocol failures use 500 server_error; transient SQLite contention uses 503 temporarily_unavailable with Retry-After.

JSON Session And Application Errors

Session services raise server exceptions for invalid credentials, invalid or expired sessions, CSRF failures, and account state. On application-owned JSON routes, FastAPI handlers translate application domain errors, request-validation errors, and plain HTTPException responses into the same envelope:

{
  "code": "UNAUTHORIZED",
  "message": "Unauthorized operation.",
  "details": []
}

code is the stable machine-readable value, message is a safe human-readable explanation, and details contains structured explanations when a request has specific violations. Each application error class owns its status, code, message, and static response headers. The runtime handler and the OpenAPI response examples consume those same values so the documented contract matches the serialized response.

On application-owned routes, Bearer access-token verification and persisted OAuth2-session failures are normalized to the application code UNAUTHORIZED. The OpenID Connect UserInfo endpoint translates both categories to the protocol error invalid_token instead.

External OAuth2 interaction routes use 400 OAUTH2_INTERACTION_INVALID for missing, expired, consumed, or user/organization-mismatched handles. This deliberately prevents the frontend from distinguishing whether an opaque handle ever existed. Interaction, session, and CSRF responses carry Cache-Control: no-store.

Request validation uses the application code VALIDATION. Its details contain only a value location, a safe message, and the Pydantic validation type. Raw input values and validation context are not returned because they may contain sensitive or non-serializable data:

{
  "code": "VALIDATION",
  "message": "Request validation failed.",
  "details": [
    {
      "location": ["body", "email"],
      "message": "Field required",
      "type": "missing"
    }
  ]
}

Browser Presentation Errors

Built-in browser routes render failures as safe HTML rather than returning the JSON envelope. This applies to authentication pages, OAuth2 interaction pages, and the /management/organization and /management/operator management interfaces. Management requests initiated by htmx receive an HTML fragment suitable for the current page.

Missing or invalid management authentication redirects to the configured login entry point. OAuth2 protocol endpoints remain separate: they return their standard protocol errors even when a browser initiated the request.

Routes list the concrete application errors they expose. When several errors share one HTTP status, OpenAPI groups them under that response. Its example keys only distinguish documentation examples; clients use the code inside the payload. Declared response headers are included in the same contract. Invalid user-list date ranges return 400 START_DATE_AFTER_END_DATE. Removing an organization's final active, verified administrator returns 409 LAST_ACTIVE_ORGANIZATION_ADMIN.

SQLite unique, check, foreign-key, and not-null failures that do not represent a recognized domain conflict use the stable application code DATA_CONFLICT and the generic message The requested data conflicts with stored data. A known collision between active normalized email addresses uses ALREADY_EXISTS, including when the database constraint resolves a concurrent ownership race. In development, DATA_CONFLICT details may contain one safe diagnostic whose type is unique_violation, check_violation, foreign_key_violation, or not_null_violation. Its location is empty because a relational constraint does not necessarily identify one HTTP field. These diagnostics never contain SQLite messages or table, column, and constraint names.

In deployment, persistence diagnostics are redacted and details is empty. Validation details remain available so clients can correct invalid requests. Clients must therefore branch only on DATA_CONFLICT; a persistence detail is diagnostic information and is not a stable deployment contract.

OAuth2 protocol errors remain separate and retain their RFC-style {"error": ...} contract.

Authentication failures preserve their WWW-Authenticate challenge. CSRF failures use 403, while absent or invalid authentication uses 401. Browser session failures return the Session challenge, bearer failures return the Bearer challenge, and a request with no credentials advertises every enabled application authentication transport (Bearer, Session when both are enabled). Transient SQLite lock failures include Retry-After.

CSRF error codes distinguish the rejected proof component. In particular, CSRF_REQUEST_SOURCE_MISSING means neither Origin nor Referer was present, while CSRF_REQUEST_SOURCE_UNTRUSTED means the supplied request source was malformed or outside the configured trusted origins. Token-cookie divergence continues to use CSRF_COOKIE_HEADER_MISMATCH.

Do not log raw passwords, session cookies, authorization codes, access tokens, refresh tokens, client secrets, or single-use workflow tokens when handling errors.