Skip to content

build(deps): pin starlette directly so it can't float under fastapi#516

Merged
mattrobinsonsre merged 3 commits into
mainfrom
fix/pin-starlette-direct
Jun 15, 2026
Merged

build(deps): pin starlette directly so it can't float under fastapi#516
mattrobinsonsre merged 3 commits into
mainfrom
fix/pin-starlette-direct

Conversation

@mattrobinsonsre

Copy link
Copy Markdown
Owner

Makes it structurally impossible to bump fastapi (or rebuild) and silently change starlette underneath us.

The gap

starlette is fastapi's dependency, but fastapi declares only a floor (starlette>=0.46, no ceiling). We never pinned it ourselves, so on every build it floats to the latest release — it is already at 1.3.1 today under fastapi 0.136.1. That means a starlette release (or a fastapi bump that raises the floor) can change framework behaviour with no deliberate, reviewed change on our side.

Note: the fastapi 0.137 breakage that started this was actually fastapi's own include_router refactor — starlette was already 1.x. But the underlying risk (starlette unpinned, floating) is real and is what this closes.

The guard

  • services/pyproject.toml: declare starlette = ">=1.3.1,<1.4.0" as a direct dependency, adjacent to fastapi with a comment. Now:
    • a starlette move requires a deliberate bump of this line;
    • a fastapi version needing a starlette outside the range fails to resolve instead of swapping it in silently.
  • services/tests/test_dependency_pins.py (new, wired into the CI unit shard): asserts starlette stays a direct dep with an upper bound, and fastapi keeps its ceiling — so the guard can't be quietly deleted.

Verification

  • Resolver dry-run with fastapi <0.137 + starlette >=1.3.1,<1.4.0 + sse-starlette → exit 0, no conflict.
  • Guard test passes against the new pyproject.toml; ruff clean.

Part of v0.38.1 alongside #512 and #513.

starlette is fastapi's dependency, but fastapi declares only a floor
(starlette>=0.46, no ceiling), so on our side it was unpinned and floated
to the latest release on every build (already at 1.3.1). Declare it as a
direct dependency with an upper bound (>=1.3.1,<1.4.0) so:

- a starlette release can't change framework behaviour without a
  deliberate, reviewed bump of this line; and
- a fastapi version that needs a starlette outside this range FAILS TO
  RESOLVE instead of swapping it in silently (the fastapi 0.137 +
  starlette 1.x trap that prompted this).

Adds tests/test_dependency_pins.py (wired into the CI unit shard) to hold
the invariant: starlette stays a direct dep with an upper bound, and
fastapi keeps its ceiling. Resolution verified (pip dry-run exit 0).
@mattrobinsonsre mattrobinsonsre enabled auto-merge (squash) June 15, 2026 10:20
@mattrobinsonsre mattrobinsonsre merged commit f80f694 into main Jun 15, 2026
52 checks passed
@mattrobinsonsre mattrobinsonsre deleted the fix/pin-starlette-direct branch June 15, 2026 10:45
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