This document explains the exception handling architecture, response code standards, and error propagation mechanisms in the FastAPI Best Architecture. It covers how different exception types are caught, transformed into standardized responses, and logged through the middleware pipeline.
For information about the middleware that captures exception data, see Middleware Pipeline. For details on how exceptions are logged, see Logging & Operation Logs.
The exception handling system provides:
All exception handlers are registered in backend/common/exception/exception_handler.py78-196 via the register_exception() function.
The application registers six exception handlers during startup, each responsible for a specific exception type:
| Handler | Exception Type | Status Code | Purpose |
|---|---|---|---|
http_exception_handler | HTTPException | As raised | Standard HTTP errors |
fastapi_validation_exception_handler | RequestValidationError | 422 | FastAPI request validation |
pydantic_validation_exception_handler | ValidationError | 422 | Pydantic model validation |
assertion_error_handler | AssertionError | 500 | Assertion failures |
custom_exception_handler | BaseExceptionError | As defined | Business logic exceptions |
all_unknown_exception_handler | Exception | 500 | Catch-all for unhandled errors |
Sources: backend/core/registrar.py76-114 backend/common/exception/exception_handler.py78-196
The following diagram shows how exceptions flow through the handling system and integrate with middleware:
Sources: backend/common/exception/exception_handler.py78-196 backend/middleware/opera_log_middleware.py55-66
All exception handlers use _get_exception_code() to validate HTTP status codes against RFC standards before returning responses. This prevents invalid status codes from causing client errors.
The function checks against Python's http.STATUS_PHRASES dictionary, which is based on the IANA HTTP Status Code Registry.
Sources: backend/common/exception/exception_handler.py17-33
All exception handlers return responses in a consistent JSON format using MsgSpecJSONResponse:
| Field | Type | Description |
|---|---|---|
code | int | HTTP status code or custom code |
msg | str | Error message |
data | any | Additional error details (dev mode only) |
trace_id | str | Request correlation ID for debugging |
The trace ID is added to every exception response via get_request_trace_id() to enable request correlation across logs and responses.
Sources: backend/common/exception/exception_handler.py74-75 backend/utils/trace_id.py5-9
Handles standard Starlette/FastAPI HTTP exceptions raised by the framework or application code.
Handler: backend/common/exception/exception_handler.py79-103
Behavior:
CustomResponseCode.HTTP_400ctx.__request_http_exception__Example Usage:
Handles Pydantic and FastAPI request validation errors with internationalization support.
Handlers:
Both handlers delegate to _validation_exception_handler() backend/common/exception/exception_handler.py36-75
Behavior:
t(f'pydantic.{error["type"]}')ctx.__request_validation_exception__Validation Error Structure:
Sources: backend/common/exception/exception_handler.py36-75 backend/common/exception/exception_handler.py105-125
Handles assertion failures in the application code.
Handler: backend/common/exception/exception_handler.py127-150
Behavior:
exc.argsCustomResponseCode.HTTP_500ctx.__request_assertion_error__Example Usage:
Handles application-specific business logic exceptions that inherit from BaseExceptionError.
Handler: backend/common/exception/exception_handler.py152-172
Behavior:
exc.backgroundctx.__request_custom_exception__Custom Exception Attributes:
| Attribute | Type | Description |
|---|---|---|
code | int | HTTP status code |
msg | str | Error message |
data | any | Optional additional data |
background | BackgroundTask | Optional background task |
Sources: backend/common/exception/exception_handler.py152-172
Catch-all handler for any unhandled exceptions.
Handler: backend/common/exception/exception_handler.py174-196
Behavior:
str(exc)CustomResponseCode.HTTP_500Sources: backend/common/exception/exception_handler.py174-196
The application uses the ENVIRONMENT setting to control error detail exposure:
| Exception Type | Development Mode | Production Mode |
|---|---|---|
| HTTPException | Full status code and detail | Generic error message |
| ValidationError | Full error list with inputs | Error message only |
| AssertionError | Assertion message | Generic error message |
| BaseExceptionError | Full exception details | Full exception details |
| Unknown Exception | Exception string | Generic error message |
Configuration: backend/core/conf.py22
Security rationale: Production mode hides implementation details that could be exploited by attackers, such as:
Sources: backend/core/conf.py22 backend/common/exception/exception_handler.py88-96 backend/common/exception/exception_handler.py136-144
Exception handlers store exception information in the ctx context object using specific marker attributes. The OperaLogMiddleware retrieves this information to populate operation logs with error details.
The OperaLogMiddleware checks for exceptions after the response is generated:
backend/middleware/opera_log_middleware.py55-66
The extracted code and msg are used to populate the operation log entry backend/middleware/opera_log_middleware.py94-115
Sources: backend/middleware/opera_log_middleware.py55-73 backend/common/exception/exception_handler.py73 backend/common/exception/exception_handler.py97 backend/common/exception/exception_handler.py145 backend/common/exception/exception_handler.py166
The application distinguishes between two types of response codes:
HTTP status codes that conform to RFC standards and the IANA registry. These are validated by _get_exception_code() before being returned to clients.
Common codes used:
HTTP_400: Bad RequestHTTP_422: Unprocessable Entity (validation errors)HTTP_500: Internal Server ErrorApplication-specific codes for business logic errors. These extend the standard codes with custom semantics while still using valid HTTP status codes as the transport mechanism.
Referenced in: backend/common/exception/exception_handler.py10 backend/common/response/response_code.py (file not provided)
Sources: backend/common/exception/exception_handler.py10 backend/common/exception/exception_handler.py17-33
Every exception response includes a trace_id field obtained via get_request_trace_id(), which retrieves the trace ID from the request context:
The trace ID is set by the ContextMiddleware (via RequestIdPlugin) and propagated through:
ctx context objectX-Request-ID)This enables end-to-end request correlation for debugging and monitoring.
Sources: backend/utils/trace_id.py5-9 backend/common/exception/exception_handler.py14 backend/common/exception/exception_handler.py74 backend/core/registrar.py167-174
HTTPException: Standard HTTP errors (404, 403, etc.)
BaseExceptionError: Business logic errors with custom codes
AssertionError: Precondition checks in development
Let Pydantic validate: For request validation, rely on Pydantic models rather than manual checks
All custom exceptions should be caught before reaching the middleware to ensure proper ctx storage. The exception handlers automatically integrate with the middleware pipeline via the ctx markers.
Sources: backend/common/exception/exception_handler.py78-196 backend/middleware/opera_log_middleware.py55-73
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.