Skip to main content

FastAPI Validation Override

Build Status codecov pypi package Supported Python versions License: MIT

FastAPI returns 422 Unprocessable Entity for every request validation failure. Many APIs, client teams, and HTTP standards treat 400 Bad Request as the correct status code for malformed input. Fixing this in FastAPI requires wiring a custom exception handler and updating the OpenAPI schema separately. override_validation_error does both in a single call.

Features

  • Single call: patches runtime exception handling and the OpenAPI schema at once
  • Any status code: use 400, 409, or any valid code instead of 422
  • anyOf merge: when a route already declares a response at the target code, the validation error schema is merged rather than overwritten
  • Custom openapi preserved: wraps any app.openapi function already installed and applies the patch on top of its output
  • Bring your own handler: handle_exceptions=False skips the built-in handler while still patching the schema
  • Idempotent: safe to call multiple times on the same app instance
  • No-op guard: status_code=422 leaves FastAPI behavior unchanged

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 invalid fields -> 400 Bad Request {"detail": [...]}

The {"detail": [...]} body is identical to FastAPI's default 422 response. Only the status code changes.

To use a different code, pass status_code:

override_validation_error(app, status_code=409)

Reference

override_validation_error

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. Calling with 422 is a no-op
handle_exceptions bool True When 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 yourself

Custom exception handler

Set handle_exceptions=False when you need a custom response body or additional logic. The OpenAPI schema is still patched.

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 validation_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
    return JSONResponse(
        status_code=400,
        content={"message": "Validation failed", "errors": exc.errors()},
    )


@app.post("/items")
async def create_item(item: Item) -> dict[str, object]:
    return item.model_dump()


override_validation_error(app, status_code=400, handle_exceptions=False)

Preserving a custom app.openapi

Call override_validation_error after assigning your custom openapi function. The library captures app.openapi at call time and wraps it, so the order matters.

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]
override_validation_error(app)  # must come after

Merging with an existing response at the target code

When a route already declares a response at the target status code, override_validation_error merges the schemas using anyOf instead of overwriting the existing one.

class OutOfStockError(BaseModel):
    message: str
    item_name: str


@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)
# schema at 400: anyOf: [OutOfStockError, HTTPValidationError]

Examples

Runnable examples are in the examples/ directory:

File Description
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

Release Notes

RELEASE_NOTES

License

MIT

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.3.tar.gz (77.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.3-py3-none-any.whl (6.4 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_validation_override-0.1.3.tar.gz.

File metadata

  • Download URL: fastapi_validation_override-0.1.3.tar.gz
  • Upload date:
  • Size: 77.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.3.tar.gz
Algorithm Hash digest
SHA256 055882aaaf1df6bc200a130dbb0bebf4c81f60c807e3dc51305cf5bdaf602bef
MD5 ad4a2dcf5ab9322929279141cf2a8f49
BLAKE2b-256 4d2d5b1a34d2c41e6c9ba23225ab452f5d0ec57fe7e0bb9db0d64bc1ca1f18ed

See more details on using hashes here.

File details

Details for the file fastapi_validation_override-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: fastapi_validation_override-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 6.4 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5aa7d7e704df9742be635a88dc92573c55796eb590cdf011507d5d3467b46489
MD5 a8e03cec49125ba2b1c4e5ba218e8837
BLAKE2b-256 2726667747c7a4c505c1373588470320a2ff5de1a6932098003cc9deffd43267

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.1

2 files

1.2.0

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

0.2.0

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page