FastAPI cookbook · Intermediate
Return RFC 9457 Problem Details from FastAPI
Make every error response — validation, not found, conflicts, crashes — use one consistent JSON shape.
Approach
Register exception handlers for your domain errors, HTTPException and RequestValidationError, all returning application/problem+json with type, title, status, detail and extra fields (like errors for validation). Add a catch-all that logs and returns a generic 500.
Solution
from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
PROBLEM = "application/problem+json"
def problem(status: int, title: str, detail: str | None = None, **extra) -> JSONResponse:
body = {"type": "about:blank", "title": title, "status": status, **({"detail": detail} if detail else {}), **extra}
return JSONResponse(body, status_code=status, media_type=PROBLEM)
@app.exception_handler(StarletteHTTPException)
async def http_error(request: Request, exc: StarletteHTTPException):
return problem(exc.status_code, exc.detail if isinstance(exc.detail, str) else "Error")
@app.exception_handler(RequestValidationError)
async def validation_error(request: Request, exc: RequestValidationError):
errors = [{"field": ".".join(str(p) for p in e["loc"][1:]), "message": e["msg"]} for e in exc.errors()]
return problem(422, "Validation failed", errors=errors)
@app.exception_handler(DomainError)
async def domain_error(request: Request, exc: DomainError):
return problem(exc.status_code, exc.title, str(exc))
@app.exception_handler(Exception)
async def unhandled(request: Request, exc: Exception):
logger.exception("Unhandled error")
return problem(500, "Internal Server Error")
Pitfalls
- Handling FastAPI's
HTTPExceptionbut not Starlette's (404s for unknown routes come from Starlette). - Leaking exception messages from unexpected errors.
- Changing error shapes between versions without notice.
Variations
- Include a
request_idfield in every problem for support.
Further reading: RFC 9457: Problem Details
Reference: https://www.rfc-editor.org/rfc/rfc9457
More FastAPI recipes
- Add liveness and readiness endpoints to FastAPI
- Add OpenTelemetry tracing to FastAPI
- Add request IDs and structured logs to FastAPI
- Build a WebSocket chat endpoint in FastAPI
- Cache FastAPI responses in Redis
- Call external APIs with retries and timeouts from FastAPI
- Implement role-based access control in FastAPI
- Isolate tenants in a multi-tenant FastAPI app