Skip to content

fix: repair the litestar and faststream floors - #220

Merged
lesnik512 merged 1 commit into
mainfrom
fix/decayed-floors
Sep 15, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
fix/decayed-floors

Conversation

@lesnik512

Copy link
Copy Markdown
Member

The two decayed floors found by the composition check in #218. Neither was a simple bump: each
turned out to rest on a dependency the upstream package uses but does not declare.

litestar>=2.19                              # was >=2.15
typing-extensions>=4.12                     # new, litestar extra
pydantic>=2.12; python_version >= '3.14'    # new, faststream extra
typing-extensions>=4.12.2                   # new, faststream extra

litestar

litestar/concurrency.py:8 does import sniffio. Until 2.19 litestar did not declare it and it
arrived through anyio, which dropped the dependency in 4.14. litestar==2.15.0 with
anyio==4.14.2 therefore raises ModuleNotFoundError: No module named 'sniffio' at
import lite_bootstrap. 2.19.0 is the first release declaring sniffio>=1.3.1.

Raising the floor exposed a second undeclared dependency underneath it: every litestar from 2.19 to
2.24 declares typing-extensions bare, while importing typing_extensions.ReadOnly (4.9). With
typing-extensions pinned at this project's own floor, the resolver has no reason to lift it, so the
floor has to be declared here:

typing-extensions 3.10 3.14
4.9.0, 4.11.0 pass AttributeError: attribute '__default__' of 'typing.ParamSpec' objects is not writable
4.12.0 pass pass

4.9 is enough for ReadOnly, but 4.9 and 4.11 assign typing.ParamSpec.__default__, which Python
3.13 made read-only. Hence >=4.12 rather than >=4.9.

faststream

faststream>=0.6 pulls fast-depends[pydantic], which allows pydantic>=1.7.4,<3.0.0. pydantic
requires typing-extensions>=4.12.2 on 3.13+, so with typing-extensions pinned at 4.8 (this
project's floor, lifted by faststream's own typing-extensions>=4.8.0) the resolver walks pydantic
back to 2.7.4, whose pydantic-core==2.18.4 builds against pyo3 0.21.2 and has no cp313 or cp314
wheel. The reported 3.14 failure was the same defect on 3.13, one interpreter earlier than #218 said.

Raising the faststream floor does not help: 0.7.5 still declares only fast-depends[pydantic]>=3.0.0,
and fast-depends 3.0.8 is the newest release. The constraint has to come from here.

typing-extensions>=4.12.2 fixes 3.10 through 3.13, landing pydantic 2.11.10. On 3.14 pydantic 2.11
still has no wheel, and 2.12 is the first that does, so that one is declared under a marker rather
than as a floor for every interpreter where 2.7.4 is fine.

Why these sit on the extras rather than on core

Both are constraints on packages lite-bootstrap never imports, declared because the chain that
reaches them is under-constrained upstream. Putting typing-extensions>=4.12.2 in
[project.dependencies] instead would be one line rather than four and would fix both, but it would
overstate core: #214 measured bare core at 4.6, and free-all still resolves 4.6.0 after this change.
Keeping the constraint where its cause is keeps the core claim honest and lets each comment name what
forced it. Worth a second opinion in review, since the alternative is genuinely simpler.

Verification

Every *-all extra under --resolution lowest-direct, on every supported interpreter, installed and
bootstrapped:

extra 3.10 3.11 3.12 3.13 3.14
free-all ok ok ok ok ok
fastapi-all ok ok ok ok ok
litestar-all ok ok ok ok ok
faststream-all ok ok ok ok ok
fastmcp-all ok ok ok ok ok

25 of 25, against 8 of 10 before. litestar-all and faststream-all additionally bootstrap and tear
down their bootstrapper, not just import.

just lint-ci and just test-ci pass (277 passed, 100% coverage). uv.lock is unchanged.

litestar 2.15 imports sniffio without declaring it and relied on anyio,
which dropped the dependency in 4.14; 2.19 is the first release that
declares it. litestar also declares typing-extensions bare while using
ReadOnly, so that floor is declared here too.

faststream pulls pydantic through fast-depends, which allows it back to
1.7.4. With typing-extensions pinned at the declared floor the chain
resolves a pydantic whose pydantic-core has no cp313 or cp314 wheel, so
both constraints are declared on the extra.
@lesnik512
lesnik512 merged commit a7c9e98 into main Sep 15, 2026
12 checks passed
@lesnik512
lesnik512 deleted the fix/decayed-floors branch September 15, 2026 18:19
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