Skip to content

fix(api): stop gzip middleware from dropping response starts on Starlette 1.8 - #9884

Merged
joshistoast merged 4 commits into
invoke-ai:mainfrom
Pfannkuchensack:bugfix/gzip-starlette-1-8
Oct 17, 2026
Merged

joshistoast merged 4 commits into
invoke-ai:mainfrom
Pfannkuchensack:bugfix/gzip-starlette-1-8

Conversation

@Pfannkuchensack

@Pfannkuchensack Pfannkuchensack commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

Since Starlette 1.8.0 (released 2026-10-13), some responses fail with RuntimeError: Expected ASGI message 'http.response.start', but got 'http.response.body'. FastAPI 0.141.1 only requires starlette>=0.46.0, so pip and launcher installs pick up 1.8.0 even though uv.lock pinned 1.7.0.

Cause: _ContentTypeAwareGZipResponder set Starlette's internal content_type_is_excluded flag after the base responder had already handled http.response.start. Starlette 1.8 now forwards the start inside that branch for the types it excludes itself, and its body branch only sends the body. So for any type that Starlette would compress but our allowlist skips, the start was buffered and never sent. Affected types include font/ttf/font/otf (user fonts), application/octet-stream and application/pdf, for any client that sends Accept-Encoding: gzip, which every browser does.

Fix: ContentTypeAwareGZipMiddleware no longer patches Starlette internals. When a response starts, it checks the content type. Compressible responses go through Starlette's public GZipMiddleware; everything else goes straight to the server. This works the same on every Starlette release FastAPI allows. uv.lock now pins Starlette 1.8.0, so CI runs the version users actually get. Only the starlette entry in the lockfile changed.

Related Issues / Discussions

Reported by about five users on Discord after upgrading.

QA Instructions

  • pytest tests/app/api/test_gzip_content_types.py: 40 passed each on Starlette 1.8.0, 1.7.0 and 0.48.0.
  • The old implementation fails 6 of the updated tests on Starlette 1.8.0 (font/ttf, application/pdf and application/octet-stream, buffered and streamed), with Received "http.response.body" without "http.response.start".
  • ruff check and ruff format --check pass on the changed files. uv lock --check passes.
  • I left the full suite to CI.

Manual repro on an affected install: with Starlette 1.8.0, curl -H 'Accept-Encoding: gzip' http://127.0.0.1:9090/api/v1/utilities/fonts/<font>.ttf (or any other font/ttf or application/octet-stream response). This logs the RuntimeError on main and serves the file with this branch.

Workaround for users until this ships: http_compression_level: 0 in invokeai.yaml, or pip install "starlette==1.7.0".

Review

No material findings. Checked: early-hint and other pre-start messages, pathsend, HEAD/206/304, errors raised mid-response together with ServerErrorMiddleware, Vary and non-gzip clients. Building the middleware per request costs about 3 µs. Responses that are not compressed skip the responder, so they are cheaper than before.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

…ette 1.8

Route each response at http.response.start through Starlette's public GZipMiddleware only when its content type compresses; send everything else directly.
Starlette 1.8 forwards the start for its own excluded types inside the responder, so the old flag patch lost it for types like font/ttf and application/octet-stream.
Lock starlette 1.8.0 so CI runs what pip/launcher installs resolve to.
@github-actions github-actions Bot added python PRs that change python files Root python-tests PRs that change python tests labels Oct 16, 2026
@joshistoast
joshistoast enabled auto-merge (squash) October 17, 2026 17:38
@joshistoast
joshistoast merged commit a1b5282 into invoke-ai:main Oct 17, 2026
17 checks passed
@Pfannkuchensack
Pfannkuchensack deleted the bugfix/gzip-starlette-1-8 branch October 19, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python PRs that change python files python-tests PRs that change python tests Root

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants