Handle RequestValidationError Globally in FastAPI
This article provides a straightforward guide to handling FastAPI's
RequestValidationError at a global level. By registering a
custom exception handler for this specific error, you can intercept
invalid incoming payload or query data, customize the default HTTP 422
response body, and maintain a consistent error structure across your
entire API application.
Understanding
RequestValidationError
When an incoming HTTP request contains data that does not conform to
your Pydantic schemas, FastAPI automatically raises a
RequestValidationError. By default, FastAPI catches this
exception and returns an HTTP 422 Unprocessable Entity status code with
a detailed list of validation errors. In production applications, you
often need to customize this response format to match your API's
standard error envelope.
The Registration Procedure
To register a global handler for RequestValidationError,
follow these steps:
1. Import Necessary Modules
You must import RequestValidationError from
fastapi.exceptions, Request and
status from fastapi, and
JSONResponse from fastapi.responses.
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel2. Define the Custom Exception Handler
Create an asynchronous function that accepts two parameters: the
incoming Request object and the caught
RequestValidationError instance. Inside the function, you
can inspect exc.errors() for validation details or
exc.body to see the raw request data. Construct and return
a JSONResponse with your desired structure.
async def validation_exception_handler(request: Request, exc: RequestValidationError):
# Extract details from the exception
errors = exc.errors()
# Structure a custom response body
custom_response = {
"success": False,
"message": "Validation failed for the request payload.",
"errors": [
{
"field": " -> ".join(str(loc) for loc in err.get("loc", [])),
"issue": err.get("msg"),
"type": err.get("type")
}
for err in errors
]
}
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=custom_response
)3. Register the Handler with the Application
You can register the handler to your FastAPI instance using either
the decorator syntax or the add_exception_handler
method.
Option A: Using the Decorator
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def custom_validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"detail": "Custom validation error message", "errors": exc.errors()}
)Option B: Using
add_exception_handler
app = FastAPI()
app.add_exception_handler(RequestValidationError, validation_exception_handler)Complete Implementation Example
Below is a complete, working example illustrating the registration and behavior of the global handler:
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
app = FastAPI()
# Register global exception handler
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"status": "error",
"error_code": "INVALID_INPUT",
"details": exc.errors()
}
)
# Sample schema
class UserItem(BaseModel):
name: str = Field(..., min_length=3)
age: int = Field(..., ge=18)
# Sample endpoint
@app.post("/users/")
async def create_user(user: UserItem):
return {"message": "User created successfully", "user": user}Whenever a client sends invalid data to /users/—such as
an age below 18 or a missing name—FastAPI
intercepts the failure and routes it through your custom global handler,
returning the formatted JSON structure instead of the default FastAPI
validation error format.