How it works¶
override_validation_error is a setup step: you call it once, and it changes two things on the app, the handler of RequestValidationError and the app.openapi function. The steps below follow the order of the code.
1. Checking the arguments¶
Every argument is checked before anything is registered on the app:
status_codemust be anint, and not abool, otherwiseTypeError. It must be between 100 and 599 and able to carry a body, so not 1xx,204or304, otherwiseValueError. Anintsubclass such ashttp.HTTPStatusis turned into a plainint.media_typemust beapplication/jsonor end in+json, otherwiseValueError.error_builder, when given, needshandle_exceptions=True(ValueError), must not beasync(TypeError), and must have a Pydantic model as its return annotation (TypeError).
When a check fails, the app is left as it was.
2. When nothing changes¶
The call returns without changing the app in two cases:
status_code=422, withouterror_builderand with the defaultmedia_type: that's what FastAPI already does.- The app was already configured by a previous call, whatever the arguments of that call.
3. The exception handler¶
With handle_exceptions=True, a handler for RequestValidationError is registered on the app. It builds the body with error_builder(exc), or as {"detail": exc.errors()} without one, encodes it with fastapi.encoders.jsonable_encoder, and returns it with status_code and media_type.
With handle_exceptions=False, no handler is registered, and the remaining steps only change the schema.
4. Wrapping app.openapi¶
app.openapi is replaced with a function that calls the one the app had before, patches the schema it returns, and stores it in app.openapi_schema. A custom app.openapi assigned before the call keeps running, with its caching. The patch runs every time the schema is generated, and the steps below are that patch.
5. Removing FastAPI's 422¶
Every operation is visited: the paths, the webhooks, and the callbacks declared inline on them. A 422 response whose application/json schema is exactly a reference to HTTPValidationError is the one FastAPI generates for validation, and is removed. Any other 422 stays.
An operation validates input, and gets the validation error at the target code, if its FastAPI 422 was removed, or if it has a request body or parameters.
6. FastAPI's components, with an error builder¶
With error_builder, FastAPI's HTTPValidationError and ValidationError components are removed, if they are still FastAPI's definitions and nothing in the schema refers to them anymore. This happens before your model is added, so a model with one of those names can take its place.
7. The response at the target code¶
For each operation that validates input:
- Without a response at the target code, one is added: described as
Validation Error, with the error's component under themedia_typekey. - With a response already there, it's left untouched if
merge_target_response=Falseor if it's a$ref. Otherwise the error's component goes under themedia_typekey of that response: alone if the key had no schema, prepended to an existinganyOfthat doesn't list it yet, or combined with the existing schema in a newanyOf.Validation Erroris appended to its description.
8. The error's component¶
The component is added to components.schemas the first time an operation needs it, so a schema with no operation that validates input gets none.
- Without an error builder, it's FastAPI's
HTTPValidationError, with theValidationErrorit refers to. Both definitions are read fromfastapi.openapi.utilswhen the schema is generated, so reassigning them before that changes what is documented. If the schema already has a different component under one of those names, aFastAPIValidationOverride_-prefixed name is used for it instead. - With an error builder, it's the schema Pydantic generates for the model in serialization mode, with the models it nests. A component with the same name and definition is reused; if any of the names is taken by a different definition, all of them get the
FastAPIValidationOverride_prefix, so the references between them stay consistent.