The Fix
Upgrade to version 0.19.0 or later.
Based on closed Kludex/starlette issue #1125 · PR/commit linked
Production note: Most teams hit this during upgrades or environment changes. Roll out with a canary and smoke critical endpoints (health, OpenAPI/docs) before 100%.
@@ -159,7 +159,7 @@ async def parse(self) -> FormData:
if type(charset) == bytes:
charset = charset.decode("latin-1")
- boundary = params.get(b"boundary")
+ boundary = params[b"boundary"]
TypeError: can't concat NoneType to bytes
File "starlette/middleware/trustedhost.py", line 51, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/sessions.py", line 75, in __call__
await self.app(scope, receive, send_wrapper)
File "cpms/middleware.py", line 55, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/authentication.py", line 48, in __call__
await self.app(scope, receive, send)
File "starlette/exceptions.py", line 82, in __call__
raise exc from None
File "starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "starlette/routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "starlette/routing.py", line 243, in handle
await self.app(scope, receive, send)
File "starlette/routing.py", line 54, in app
response = await func(request)
File "starlette/authentication.py", line 69, in async_wrapper
return await func(*args, **kwargs)
File "cpms/views/files.py", line 90, in decorator
return await endpoint(request)
File "cpms/views/files.py", line 133, in upload_files
for f_name, f_value in (await request.form()).items():
File "starlette/requests.py", line 240, in form
self._form = await multipart_parser.parse()
File "starlette/formparsers.py", line 181, in parse
parser = multipart.MultipartParser(boundary, callbacks)
File "multipart/multipart.py", line 1042, in __init__
self.boundary = b'\r\n--' + boundary
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 0.19.0 or later.\nWhen NOT to use: This fix should not be used if the application requires a different error handling strategy.\n\n
Why This Fix Works in Production
- Trigger: TypeError: can't concat NoneType to bytes
- Mechanism: Insufficient input validation for the boundary parameter in multipart form data
- Why the fix works: Raises a KeyError when the boundary parameter is missing in multipart form data, ensuring early error handling. (first fixed release: 0.19.0).
- If left unfixed, the same config can fail only in production (env differences), causing startup failures or partial feature outages.
Why This Breaks in Prod
- Insufficient input validation for the boundary parameter in multipart form data
- Surfaces as: TypeError: can't concat NoneType to bytes
Proof / Evidence
- GitHub issue: #1125
- Fix PR: https://github.com/kludex/starlette/pull/1349
- First fixed release: 0.19.0
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.85
- 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).
“I think this can be considered a bug, because we send 500 instead of 4xx, and you're right: this is actually a client error. I'd…”
“Flask uses werkzeug's FormDataParser with the following code:”
Failure Signature (Search String)
- TypeError: can't concat NoneType to bytes
Error Message
Stack trace
Error Message
-------------
TypeError: can't concat NoneType to bytes
File "starlette/middleware/trustedhost.py", line 51, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/sessions.py", line 75, in __call__
await self.app(scope, receive, send_wrapper)
File "cpms/middleware.py", line 55, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/authentication.py", line 48, in __call__
await self.app(scope, receive, send)
File "starlette/exceptions.py", line 82, in __call__
raise exc from None
File "starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "starlette/routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "starlette/routing.py", line 243, in handle
await self.app(scope, receive, send)
File "starlette/routing.py", line 54, in app
response = await func(request)
File "starlette/authentication.py", line 69, in async_wrapper
return await func(*args, **kwargs)
File "cpms/views/files.py", line 90, in decorator
return await endpoint(request)
File "cpms/views/files.py", line 133, in upload_files
for f_name, f_value in (await request.form()).items():
File "starlette/requests.py", line 240, in form
self._form = await multipart_parser.parse()
File "starlette/formparsers.py", line 181, in parse
parser = multipart.Multip
... (truncated) ...
Minimal Reproduction
TypeError: can't concat NoneType to bytes
File "starlette/middleware/trustedhost.py", line 51, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/sessions.py", line 75, in __call__
await self.app(scope, receive, send_wrapper)
File "cpms/middleware.py", line 55, in __call__
await self.app(scope, receive, send)
File "starlette/middleware/authentication.py", line 48, in __call__
await self.app(scope, receive, send)
File "starlette/exceptions.py", line 82, in __call__
raise exc from None
File "starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "starlette/routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "starlette/routing.py", line 243, in handle
await self.app(scope, receive, send)
File "starlette/routing.py", line 54, in app
response = await func(request)
File "starlette/authentication.py", line 69, in async_wrapper
return await func(*args, **kwargs)
File "cpms/views/files.py", line 90, in decorator
return await endpoint(request)
File "cpms/views/files.py", line 133, in upload_files
for f_name, f_value in (await request.form()).items():
File "starlette/requests.py", line 240, in form
self._form = await multipart_parser.parse()
File "starlette/formparsers.py", line 181, in parse
parser = multipart.MultipartParser(boundary, callbacks)
File "multipart/multipart.py", line 1042, in __init__
self.boundary = b'\r\n--' + boundary
What Broke
A 500 error is returned instead of a 4xx client error when boundary is missing.
Why It Broke
Insufficient input validation for the boundary parameter in multipart form data
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.19.0 or later.
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/1349
First fixed release: 0.19.0
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be used if the application requires a different error handling strategy.
Verify Fix
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
- Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
- Pin production dependencies and upgrade only with a reproducible test that hits the failing path.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.19.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.