Skip to main content

Override FastAPI's 422 with any HTTP status code — at runtime and in the OpenAPI schema.

Project description

FastAPI Validation Override

PyPI License: MIT Python

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.openapi function already defined is called first; the patch is applied on top
  • Custom exception handler — set handle_exceptions=False to 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

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_validation_override-0.1.0.tar.gz (74.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_validation_override-0.1.0-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

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

Hashes for fastapi_validation_override-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a79a506aa9075fde4f8f6978182c821193b4aac8ab8bb6d8c1dc50b48e368b66
MD5 aa19bd7c5917c700a345bad892f43a7f
BLAKE2b-256 c3f6b1719a153ef9379668b13235a3f6369ec8a26aa08c67d93adf1bd9219114

See more details on using hashes here.

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

Hashes for fastapi_validation_override-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b88a12dc9b7df718dec9ee21114c4f6bb929cdad7a66c2167f4ee93c0dbc1c29
MD5 6bfb541beefc89c52273bbcaba3cabec
BLAKE2b-256 41901e3c4eb67129725c62eb0344d1f02cd5fd7c8711edb9c24217e6f8abe6e2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page