An upload limit protects the boundary where it is enforced. Distinguish a declared Content-Length, bytes actually received, multipart parser limits, per-file validation and the total request budget. A handler that rejects an oversized file after reading it has a different resource profile from a gateway that stops the request earlier. Test the exact installed stack instead of assuming one setting covers every layer.
Count more than the largest file
Write separate budgets for whole-request bytes, number of parts, non-file field size, individual file size and decoded content. Multiple small files can exceed a total request budget even when each file is valid. Compressed or encoded content can create another processing boundary. A MIME header is client-supplied metadata, so keep content validation separate from size enforcement.
Starlette's request documentation exposes multipart parsing controls and UploadFile behavior. Their exact semantics depend on the installed version and parser implementation. In particular, do not assume a part-size setting is a complete aggregate file-upload limit without testing which part types it covers. Record FastAPI, Starlette and python-multipart versions together with any upstream proxy limit.
Starlette: request streaming, multipart parsing and UploadFile
A synthetic multipart budget
Suppose a disposable endpoint allows three files of at most 2 MiB each but has a total request budget of 5 MiB. Three files of 1.8 MiB pass the per-file rule yet exceed the aggregate budget before multipart framing is counted. The endpoint contract must state which limit wins and return a useful error. These are invented test limits, not the configuration of a deployed application.
| Input | Per-file rule | Aggregate rule |
|---|---|---|
| One 1.8 MiB file | Passes 2 MiB example | Within 5 MiB example |
| Three 1.8 MiB files | Each passes | Exceeds total before framing |
| One 2.1 MiB file | Fails individual rule | Reject and clean up |
| Many tiny fields | Not a file check | Part-count and total limits apply |
At the receive boundary, count actual chunks rather than trusting Content-Length alone. A missing or inaccurate declared length does not make the body unbounded by policy. Depending on the ASGI server and gateway, enforcement can happen before parsing, during streaming or after spooling. Design cancellation and cleanup with that specific layer; a response sent after rejection does not prove the server stopped receiving or processing the remaining body.
Proposed upload evidence record
request_budget_bytes: agreed synthetic value
declared_length: present / absent / inconsistent
actual_received_bytes: measured by enforcement layer
parsed_parts: measured separately
temporary_files_after_rejection: must be inspected
public_result: documented 413 or validation responseValidate content after resource boundaries
After basic size and parser checks, verify that the file is an accepted content type using the application's chosen inspection or decode path. A filename extension and uploaded content_type can be useful hints but are not authoritative content validation. Image decoding, document conversion and antivirus workflows each need their own resource limits and failure handling; do not hide those costs inside a single upload-size number.
Keep a durable upload operation identity if storage transfer and record creation are separate steps. Rejection after an object has already been written requires a cleanup or reconciliation policy. A retry should not create orphaned objects under unrelated identities. For purely temporary parsing, verify that both successful and failed requests close files and release descriptors before calling cleanup complete.
Test the layers without real media
Generate small byte fixtures with controlled sizes and harmless multipart fields. Test one valid file, an oversized file, too many fields, an aggregate overflow, no declared length and a cancelled transfer. Run through the actual gateway when validating gateway behavior and directly against the ASGI stack when isolating application behavior. Record where the request stopped and what disk or memory resources remained.
No upload fixture was executed for this article. The worksheet is a proposed experiment, and parser-version differences remain an explicit boundary to verify. A useful release claim names the measured limit and enforcement layer. Saying uploads are limited without that detail leaves operators unable to distinguish a per-file business rule from protection of the process receiving the request.
React Native background upload queue
Building UltraFit360: the app, coach portal and shared backend
Bring one API or data workflow and a sanitized failure example for a bounded implementation assessment.
Where should FastAPI upload size limits be enforced?
At each intended resource boundary: total received bytes, multipart parsing, individual files and decoded content, with cleanup tested on rejection and cancellation.
Is Content-Length enough to enforce upload limits?
No. Validate actual received bytes and test missing or inconsistent declarations at the chosen receive boundary.
Does a per-file check limit the whole request?
No. Multiple valid files and fields can exceed the aggregate request budget.
