Jump to solution
Verify

The Fix

Upgrade to version 0.20.1 or later.

Based on closed Kludex/starlette issue #1303 · PR/commit linked

Jump to Verify Open PR/Commit
@@ -30,6 +30,7 @@ filterwarnings= ignore: run_until_first_complete is deprecated and will be removed in a future version.:DeprecationWarning ignore: starlette\.middleware\.wsgi is deprecated and will be removed in a future release\.*:DeprecationWarning + ignore: Async generator 'starlette\.requests\.Request\.stream' was garbage collected before it had been exhausted.*:ResourceWarning [coverage:run]
repro.py
from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.routing import Route async def handler(request): return JSONResponse({k: v for k, v in (await request.form()).items()}) app = Starlette( debug=True, routes=[ Route("/", handler, methods=["POST"]), ], )
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Upgrade to fixed release\nUpgrade to version 0.20.1 or later.\nWhen NOT to use: This fix is not applicable if the application does not handle multipart/form-data requests.\n\n

Why This Fix Works in Production

  • Trigger: % curl -F '=bar' localhost:8000
  • Mechanism: The multipart/form-data parser raises a KeyError when a subpart lacks a 'name' parameter in its Content-Disposition header
  • Why the fix works: Raise `MultiPartException` when missing "name" field on `Content-Disposition` header to prevent KeyError. (first fixed release: 0.20.1).

Why This Breaks in Prod

  • Shows up under Python 3.9 in real deployments (not just unit tests).
  • The multipart/form-data parser raises a KeyError when a subpart lacks a 'name' parameter in its Content-Disposition header
  • Surfaces as: % curl -F '=bar' localhost:8000

Proof / Evidence

  • GitHub issue: #1303
  • Fix PR: https://github.com/kludex/starlette/pull/1643
  • First fixed release: 0.20.1
  • Reproduced locally: No (not executed)
  • Last verified: 2026-02-09
  • Confidence: 0.95
  • Did this fix it?: Yes (upstream fix exists)
  • Own content ratio: 0.26

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“### Checklist <!-- Please make sure you check all these items before submitting your bug report. --> - [x] The bug is reproducible against the latest release and/or master. - [x] There are no similar issues or pull requests to fix it yet. #”
Issue thread · issue description · source

Failure Signature (Search String)

  • % curl -F '=bar' localhost:8000

Error Message

Stack trace
error.txt
Error Message ------------- % curl -F '=bar' localhost:8000 Traceback (most recent call last): File "/tmp/github/venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__ await self.app(scope, receive, _send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__ raise exc File "/tmp/github/venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__ await self.app(scope, receive, sender) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 656, in __call__ await route.handle(scope, receive, send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 259, in handle await self.app(scope, receive, send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 61, in app response = await func(request) File "/tmp/github/./multipart-buglette.py", line 7, in handler return JSONResponse({k: v for k, v in (await request.form()).items()}) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/requests.py", line 247, in form self._form = await multipart_parser.parse() File "/tmp/github/venv/lib/python3.9/site-packages/starlette/formparsers.py", line 212, in parse field_name = _user_safe_decode(options[b"name"], charset) KeyError: b'name'
Stack trace
error.txt
Error Message ------------- % curl -H 'Content-Type: multipart/form-data' -d 'bogus' localhost:8000 Traceback (most recent call last): File "/tmp/github/venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__ await self.app(scope, receive, _send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__ raise exc File "/tmp/github/venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__ await self.app(scope, receive, sender) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 656, in __call__ await route.handle(scope, receive, send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 259, in handle await self.app(scope, receive, send) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/routing.py", line 61, in app response = await func(request) File "/tmp/github/./multipart-buglette.py", line 7, in handler return JSONResponse({k: v for k, v in (await request.form()).items()}) File "/tmp/github/venv/lib/python3.9/site-packages/starlette/requests.py", line 247, in form self._form = await multipart_parser.parse() File "/tmp/github/venv/lib/python3.9/site-packages/starlette/formparsers.py", line 177, in parse parser = multipart.MultipartParser(boundary, callbacks) File "/tmp/github/venv/lib/python3. ... (truncated) ...

Minimal Reproduction

repro.py
from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.routing import Route async def handler(request): return JSONResponse({k: v for k, v in (await request.form()).items()}) app = Starlette( debug=True, routes=[ Route("/", handler, methods=["POST"]), ], )

Environment

  • Python: 3.9

What Broke

Requests with missing 'name' parameters in multipart/form-data lead to server errors and unhandled exceptions.

Why It Broke

The multipart/form-data parser raises a KeyError when a subpart lacks a 'name' parameter in its Content-Disposition header

Fix Options (Details)

Option A — Upgrade to fixed release Safe default (recommended)

Upgrade to version 0.20.1 or later.

When NOT to use: This fix is not applicable if the application does not handle multipart/form-data requests.

Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.

Fix reference: https://github.com/kludex/starlette/pull/1643

First fixed release: 0.20.1

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix is not applicable if the application does not handle multipart/form-data requests.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Add a TLS smoke test that performs a real handshake in CI (include CA bundle validation and hostname checks).
  • Alert on handshake failures by error string and endpoint to catch cert/CA changes quickly.

Version Compatibility Table

VersionStatus
0.20.1 Fixed

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.