Override FastAPI's 422 with any HTTP status code — at runtime and in the OpenAPI schema.
Project description
FastAPI Validation Override
Override FastAPI's default 422 Unprocessable Entity validation error with any HTTP status code — both at runtime and in the OpenAPI schema.
Call override_validation_error(app) once after defining your routes. Validation errors will return the chosen status code with the standard {"detail": [...]} body.
Features
- Runtime + schema — patches both the exception handler and the OpenAPI schema in one call
- Any status code — use 400, 409, or any other code instead of 422
- Schema-aware merge — if a route already declares a response at the target code, the validation error schema is merged using
anyOf - Custom OpenAPI preserved — any
app.openapifunction already defined is called first; the patch is applied on top - Custom exception handler — set
handle_exceptions=Falseto patch only the schema and handle the exception independently - Idempotent calls — safe to invoke multiple times on the same app instance
Requirements
- Python ≥ 3.10
- FastAPI ≥ 0.120.0
Installation
pip install fastapi-validation-override
# or
uv add fastapi-validation-override
Quick start
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi_validation_override import override_validation_error
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items")
async def create_item(item: Item) -> dict[str, object]:
return item.model_dump()
override_validation_error(app)
# POST /items with missing fields -> 400 Bad Request {"detail": [...]}
The 422 entry in the Swagger UI is replaced by 400 automatically.
override_validation_error reference
override_validation_error(app, status_code=400, handle_exceptions=True)
| Parameter | Type | Default | Description |
|---|---|---|---|
app |
FastAPI |
required | The FastAPI application instance to patch |
status_code |
int |
400 |
HTTP status code to use instead of 422 |
handle_exceptions |
bool |
True |
If True, registers an exception handler that returns the custom status code at runtime. Set to False to patch only the OpenAPI schema and handle the exception independently |
Calling with status_code=422 is a no-op — the default FastAPI behaviour is preserved unchanged.
Advanced options
Custom status code
override_validation_error(app, status_code=409)
# Validation errors -> 409 Conflict
Custom exception handler
Set handle_exceptions=False to define a custom response body or add logic on validation errors. The OpenAPI schema is still patched to reflect the correct status code.
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from fastapi_validation_override import override_validation_error
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def custom_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
return JSONResponse(
status_code=400,
content={
"message": "Validation failed",
"errors": exc.errors(),
},
)
override_validation_error(app, status_code=400, handle_exceptions=False)
Preserving a custom app.openapi
If app.openapi has been replaced with a custom function, override_validation_error wraps it — the custom function is called first and the patch is applied to its output.
from typing import Any
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from fastapi_validation_override import override_validation_error
app = FastAPI()
def custom_openapi() -> dict[str, Any]:
if app.openapi_schema:
return app.openapi_schema
schema = get_openapi(title="My API", version="1.0.0", routes=app.routes)
schema["info"]["x-logo"] = {"url": "https://example.com/logo.png"}
app.openapi_schema = schema
return schema
app.openapi = custom_openapi # type: ignore[method-assign] # ty: ignore[invalid-assignment]
override_validation_error(app)
# x-logo is preserved; 422 is replaced by 400 in the schema
Existing response at target code
When a route already declares a response at the target status code, the validation error schema is merged into it using anyOf — neither schema is lost.
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi_validation_override import override_validation_error
app = FastAPI()
class OutOfStockError(BaseModel):
message: str
item_name: str
class Item(BaseModel):
name: str
price: float
@app.post("/items", responses={400: {"model": OutOfStockError, "description": "Out of stock"}})
async def create_item(item: Item) -> dict[str, object]:
return item.model_dump()
override_validation_error(app)
# responses.400.content.application/json.schema -> anyOf: [OutOfStockError, HTTPValidationError]
Usage with APIRouter
override_validation_error applies to the whole application, regardless of how routes are organized.
from fastapi import APIRouter, FastAPI
from pydantic import BaseModel
from fastapi_validation_override import override_validation_error
app = FastAPI()
items_router = APIRouter(prefix="/items", tags=["items"])
users_router = APIRouter(prefix="/users", tags=["users"])
# ... define routes on each router ...
app.include_router(items_router)
app.include_router(users_router)
override_validation_error(app)
Examples
Runnable examples are available in the examples/ directory:
| File | What it shows |
|---|---|
basic.py |
Minimal setup with the default 400 status code |
custom_status_code.py |
Using a custom status code (409) |
handle_exceptions_false.py |
Custom exception handler with schema-only patch |
custom_openapi.py |
Preserving a custom app.openapi function |
existing_response_at_target_code.py |
anyOf merge when the target code is already declared |
with_apirouter.py |
Usage with multiple APIRouter instances |
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_validation_override-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_validation_override-0.1.0.tar.gz
- Upload date:
- Size: 74.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a79a506aa9075fde4f8f6978182c821193b4aac8ab8bb6d8c1dc50b48e368b66
|
|
| MD5 |
aa19bd7c5917c700a345bad892f43a7f
|
|
| BLAKE2b-256 |
c3f6b1719a153ef9379668b13235a3f6369ec8a26aa08c67d93adf1bd9219114
|
File details
Details for the file fastapi_validation_override-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_validation_override-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b88a12dc9b7df718dec9ee21114c4f6bb929cdad7a66c2167f4ee93c0dbc1c29
|
|
| MD5 |
6bfb541beefc89c52273bbcaba3cabec
|
|
| BLAKE2b-256 |
41901e3c4eb67129725c62eb0344d1f02cd5fd7c8711edb9c24217e6f8abe6e2
|