Skip to content

Fix injection in mounted apps, late routes and stacked subscribers - #330

Merged
antonrh merged 1 commit into
mainfrom
fix-extensions
Aug 31, 2026
Merged

antonrh merged 1 commit into
mainfrom
fix-extensions

Conversation

@antonrh

@antonrh antonrh commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Four bugs the extension review found, each reproduced first.

A mounted sub-application was invisible

_iter_routes walked included routers but not Mount, so a sub-app's routes
were never validated, and get_container read connection.app.state, which
for a mounted app is the sub-app's own state that nobody filled:

/sub/greet raised AttributeError: 'State' object has no attribute 'container'

install() now walks mounted applications and gives each one the container,
and the container is looked up in the ASGI scope first, since a mounted app
replaces scope["app"] with itself. When there is no container anywhere, the
failure says so instead of surfacing a Starlette attribute error.

A route added after install() failed at request time

install() walked app.routes once, so anything registered later reached the
handler unwired and died with TypeError: Dependency type is not set., naming
neither the route nor the parameter. install() now watches
add_api_route, add_api_websocket_route, include_router and mount, so a
late route is validated as it is added, with the same message a route present
at install time gets.

Only the first handler of a subscriber was injected

_get_broker_handlers read subscriber.calls[0].handler. A subscriber
decorated more than once, the normal way to attach filtered handlers to one
topic, left every handler after the first without an owner, and the failure
appeared only when a message routed to it.

pydantic_settings.install() could not run twice

A second call, which an app factory called per test does, died with
LookupError: The provider Annotated[str, 'settings.name'] is already registered — naming neither the settings class nor the field. It now names
both, and takes override=True for the case where installing again is the
point.

Both landing changes are documented: "Mounted applications" on the FastAPI
page and "Installing twice" on the pydantic-settings page.

@codspeed

codspeed Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 17 untouched benchmarks


Comparing fix-extensions (7381caa) with main (f481f80)

Open in CodSpeed

`install()` now descends into mounted applications, keeps validating routes
added after it runs, and the middleware leaves the container in the ASGI scope
so a mounted app can reach it. The FastStream extension wires every handler of
a subscriber, not just the first. Installing settings twice names the model and
the field that collided, and takes `override=True`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@antonrh
antonrh merged commit 997ce45 into main Aug 31, 2026
10 checks passed
@antonrh
antonrh deleted the fix-extensions branch August 31, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant