Custom RequestValidationError & HTTP Status Code Mapping
- Last updated
- Prerequisites:
- FastAPI HTTP exceptions
- Pydantic ValidationError structure
- fastapi
- exception-handlers
- validation-error
- http-exception
- error-handling
Read at your depth
The practical view
You register custom exception handlers in FastAPI using `@app.exception_handler(ExceptionClass)`. To customize default 422 validation errors, override `RequestValidationError`: `@app.exception_handler(RequestValidationError) async def validation_handler(request: Request, exc: RequestValidationError): return JSONResponse(status_code=400, content={'errors': ...})`. You can also create custom business domain exceptions.
The same idea in other frameworks
`@app.exception_handler(CustomError)` returning `JSONResponse`.`@Catch(CustomError)` implementing `ExceptionFilter`.`@ControllerAdvice` with `@ExceptionHandler(CustomException.class)`.Express 4-argument error middleware `app.use((err, req, res, next) => ...)`.Legacy vs modern
Default Verbose 422 Error vs Clean Standardized Error Envelope
Default FastAPI 422 errors expose internal schema details; custom exception handlers standardize error envelopes.
// Default FastAPI validation response exposes raw Pydantic detail lists@app.exception_handler(RequestValidationError) async def handler(req, exc): ... // ✅ NEWInterview gotchas
Context
Interviewers test your knowledge of FastAPI vs Starlette exception inheritance.
The mechanical answer
`fastapi.HTTPException` inherits from `starlette.exceptions.HTTPException`. The difference is that `fastapi.HTTPException` accepts a `headers` parameter and allows passing any JSON-serializable structure to `detail` (dict, list, string), whereas Starlette's only accepts strings. Always import and raise `fastapi.HTTPException` in FastAPI applications.
Trap
If you register an exception handler specifically for `starlette.exceptions.HTTPException`, it will catch `fastapi.HTTPException` too, but accessing `exc.headers` may require `getattr`.
Context
Checks understanding of lifecycle execution boundaries in ASGI.
The mechanical answer
Because `BackgroundTasks` execute **after the HTTP response has already been sent and the connection is closed**. By the time the background task executes, the HTTP status code and response body are already committed to the client socket, so the exception handler cannot construct a new HTTP error response.
Trap
Always wrap code inside background tasks in custom `try...except` logging blocks.