Limitations and internals¶
An honest list of what is out of scope and why — plus a little about the internals.
FastAPI versions¶
The dependency is fastapi >=0.115,!=0.137.*,!=0.138.*.
FastAPI 0.137 introduced the lazy routing model (an _IncludedRouter tree instead of copying routes), but the supported iter_route_contexts iterator only appeared in 0.139. In the 0.137–0.138 gap nested include_routers cannot be walked correctly, so those versions are excluded at the dependency level. Two working regimes remain:
≤ 0.136— the old eagerinclude_router(a flatrouteswalk);≥ 0.139— lazy routing withiter_route_contexts.
The CI checker picks the right regime automatically (a call-time getattr plus a fallback to the flat walk).
Walker limitations¶
auto=True and check_raises share one AST walker. It is conservative and never executes your code — hence its scope.
It understands:
raise X(...),raise X,raise X(...) from e;raiseinsideif/try-except/match;- helpers called by name (cross-module too), down to a given depth;
- the
get_or_404(error=X)factory pattern (the error class as a call argument); - errors captured in a closure;
partialendpoints,functools.wrapschains, callable instances, class dependencies (via__init__);- the whole
Dependstree (security schemes are skipped).
It does not see (documented false negatives):
- local dataflow:
err = NotFoundError; raise err(...); - method chains on objects:
self.service.raise_it(); - dynamic dispatch (a
raisefrom a dict value, etc.); - bare stream returns
-> Annotated[AsyncIterator[X], Raises[...]].
False negatives are safe for CI
Because of them, overdeclared stays a failure by default. If you have dynamic raises the walker can't see — declare them explicitly with Raises, or use check_raises(app, allow_overdeclared=True).
Flat response bodies¶
Your own response model extends flat only (fields next to code/detail). Nested envelopes (data: ErrorResponse[T]) are not supported — pydantic can't discriminate a union on a nested field. See Customization for details.
Semi-internal FastAPI functions¶
auto=True rebuilds the dependency tree at registration via fastapi.dependencies.utils.get_dependant / get_parameterless_sub_dependant. These are public (no leading underscore) functions that FastAPI itself imports in routing.py, but they are not documented as a stable API. The import is wrapped in try/except ImportError — if the internal API changes, the walk degrades gracefully to "endpoint only" (dependency errors won't reach auto, but the package keeps working).
Scope of Raises on a route¶
- A
Raisesmarker on a router not passed throughwith_errorsis inert: nothing is injected and nothing fails. The CI checker reads annotations directly, so it still catches such drift. - Wrap the router before registering routes — otherwise they are not retrofitted.
Next: the API Reference — signatures from the docstrings.