Skip to main content

App-Level Exception Handling

To catch and process specific exceptions or HTTP status codes globally in your application, use the @app.exception_handler() decorator on your FastAPI instance.

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

class UnicornException(Exception):
def __init__(self, name: str):
self.name = name

app = FastAPI()

@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
)

@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
if name == "yolo":
raise UnicornException(name=name)
return {"unicorn_name": name}

How Exception Handlers Work

When you use @app.exception_handler(exc_class_or_status_code), you register a custom function to handle a specific type of error.

  • Arguments: The handler function must be async and accept two arguments: a Request object and the exception instance (or the status code if handling an int).
  • Return Value: The function must return a Response (such as JSONResponse, HTMLResponse, or a plain Response).
  • Registration: This decorator calls self.add_exception_handler internally to update the exception_handlers dictionary in the FastAPI class.

Handling HTTP Status Codes

You can register handlers for specific HTTP status codes instead of exception classes. This is useful for customizing standard error pages like 404 Not Found.

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(404)
async def not_found_handler(request: Request, exc: Exception):
return JSONResponse(
status_code=404,
content={"message": "The resource you are looking for does not exist."},
)

Overriding Default Handlers

FastAPI provides default handlers for HTTPException and RequestValidationError. You can override these to customize the response format while still utilizing the original logic if needed.

from fastapi import FastAPI
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()

@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f"Logging HTTP error: {exc.detail}")
# Call the original default handler to return the standard response
return await http_exception_handler(request, exc)

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
# Return a custom structure for validation errors
return JSONResponse(
status_code=422,
content={"custom_error_list": exc.errors(), "message": "Invalid data sent"},
)

Bulk Registration via Constructor

If you prefer to define your handlers elsewhere, you can pass them as a dictionary to the FastAPI constructor using the exception_handlers parameter.

from fastapi import FastAPI
from my_app.exceptions import UnicornException, unicorn_handler

# Map exception classes or status codes to their handler functions
handlers = {
UnicornException: unicorn_handler,
404: not_found_handler
}

app = FastAPI(exception_handlers=handlers)

Troubleshooting and Gotchas

FastAPI vs Starlette HTTPException FastAPI has its own HTTPException (in fastapi.exceptions) which inherits from Starlette's HTTPException. The FastAPI version allows you to add custom headers. When catching HTTP exceptions:

  • If you catch starlette.exceptions.HTTPException, it will catch both Starlette and FastAPI HTTP exceptions.
  • If you catch fastapi.exceptions.HTTPException, it will only catch the FastAPI version.

Handler Inheritance Handlers follow standard Python inheritance. If you register a handler for the base Exception class, it will catch all exceptions that do not have a more specific handler registered.

Re-using Default Logic The default handlers are available in fastapi.exception_handlers:

  • http_exception_handler: Handles StarletteHTTPException.
  • request_validation_exception_handler: Handles Pydantic validation errors (RequestValidationError).
  • websocket_request_validation_exception_handler: Handles validation errors in WebSockets.