Spaces:
Running
Error Handling in FastAPI
FastAPI provides a structured approach to error handling using HTTP exceptions, custom exception handlers, and validation error customization. Proper error handling ensures clients receive meaningful, consistent error responses.
HTTPException
The HTTPException class is the primary way to return error responses from route handlers:
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {"widget": {"name": "Widget", "price": 35.99}}
@app.get("/items/{item_id}")
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,
detail="Item not found",
headers={"X-Error-Code": "ITEM_NOT_FOUND"},
)
return items[item_id]
When raised, HTTPException immediately terminates request processing and returns the specified status code and detail message. The detail parameter can be a string, list, or dictionary -- FastAPI serializes it to JSON automatically. The optional headers parameter adds custom HTTP headers to the error response.
The default error response format is:
{
"detail": "Item not found"
}
Custom Exception Handlers
Register custom handlers for any exception type using @app.exception_handler():
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
class ItemNotFoundException(Exception):
def __init__(self, item_id: str):
self.item_id = item_id
app = FastAPI()
@app.exception_handler(ItemNotFoundException)
async def item_not_found_handler(request: Request, exc: ItemNotFoundException):
return JSONResponse(
status_code=404,
content={
"error": "item_not_found",
"message": f"Item '{exc.item_id}' does not exist",
"path": str(request.url),
},
)
@app.get("/items/{item_id}")
async def read_item(item_id: str):
if item_id not in items_db:
raise ItemNotFoundException(item_id)
return items_db[item_id]
Custom exception handlers receive the Request object and the exception instance. They must return a Response object (typically JSONResponse). You can register handlers for any Python exception class, including built-in exceptions like ValueError or RuntimeError.
Handling Validation Errors
FastAPI automatically returns a 422 Unprocessable Entity response when request validation fails. The default response includes detailed error information:
{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "abc",
"url": "https://errors.pydantic.dev/2/v/int_parsing"
}
]
}
Each error object contains 5 fields: type (the error type identifier), loc (the location as a list like ["body", "price"] or ["query", "limit"]), msg (a human-readable message), input (the invalid value), and url (a link to Pydantic's error documentation).
To customize validation error responses, override the RequestValidationError handler:
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request, exc: RequestValidationError
):
error_messages = []
for error in exc.errors():
field = " -> ".join(str(loc) for loc in error["loc"])
error_messages.append(f"{field}: {error['msg']}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"error": "validation_error",
"message": "Request validation failed",
"details": error_messages,
"error_count": len(exc.errors()),
},
)
Overriding Default Exception Handlers
FastAPI has built-in handlers for HTTPException and RequestValidationError. You can override both:
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
return JSONResponse(
status_code=exc.status_code,
content={
"error": True,
"status_code": exc.status_code,
"message": exc.detail,
},
)
Note: FastAPI's HTTPException inherits from Starlette's HTTPException. To override the handler for all HTTP exceptions (including those raised by Starlette internals like 404 for missing routes), register the handler for StarletteHTTPException rather than FastAPI's version.
Returning the Request Body in Errors
The RequestValidationError object contains the original request body, which can be useful for logging or debugging:
@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=422,
content={
"detail": exc.errors(),
"body": exc.body, # The raw request body that failed validation
},
)
The exc.body attribute holds the parsed request body (as a Python object) before validation was applied. This is only available for body validation errors, not for path or query parameter errors.