
Small files upload successfully, but larger ones fail with HTTP 413—even after you raise the limit at the origin. Start by finding which component rejects the request. The CDN, gateway, reverse proxy, and application can each enforce a different limit; changing a setting farther down the path will not fix a rejection upstream.
This guide covers HTTP file-upload endpoints. The commands are examples for an authorized test environment, not instructions to send test data to a live business endpoint. No production upload tests were performed for this article.
Find the rejecting layer before changing a limit
HTTP 413 Content Too Large means the recipient will not process the request because its content exceeds the size it is willing or able to handle. It may end the request early, so an upload that stops partway through can still be a size-limit problem. A temporary restriction may include Retry-After; repeatedly submitting the same request will not resolve a fixed maximum.[1]
Capture the failing URL, method, timestamp, file size in bytes, form fields, response status, and request identifier. Treat the error-page design and Server header as clues, not proof: an intermediary may replace them. Correlate CDN or edge logs with origin ingress and application logs.
If the request reaches the origin ingress but never reaches the application, investigate the gateway and reverse proxy first. If no origin entry appears, confirm that you are looking at the right logs and that collection is complete before blaming the CDN.
Measure the request body, not just the file
A multipart/form-data upload includes boundaries, part headers, and other fields in addition to the file. With multiple files, the limit may apply to their combined request body. curl's -F option builds a multipart form.[3]
In a test environment, use two otherwise valid samples near the observed success/failure boundary. Keep the file type, content, authentication, and field name consistent with the endpoint's requirements; an authorization or file-validation failure can obscure the size check.
The following example uses Bash on Linux or macOS with curl. Prepare a small, non-sensitive sample.bin first. Replace the URL with an endpoint explicitly approved for upload testing; file is only an example field name.
URL='https://upload.example.com/api/upload-test'
curl --connect-timeout 10 --max-time 120 -sS \
-D upload.headers -o upload.response \
-w 'status=%{http_code} uploaded=%{size_upload}\n' \
-F '[email protected]' "$URL"The command neither retries automatically nor follows redirects. Add authentication only through the endpoint's approved security procedure, and keep credentials out of shared files and logs. size_upload reports the amount actually sent; an early rejection can make it smaller than the complete request body.[3]
For an origin comparison, add the following options to the same curl command only when direct access is authorized, allowed by the origin, and compatible with certificate validation. Keep the original hostname in the URL:
--noproxy '*' --resolve upload.example.com:443:203.0.113.10
This is an option fragment, not a standalone command. Replace the documentation IP with the authorized origin address. An origin restricted to CDN traffic or requiring CDN-specific authentication may not accept this test. Do not leave the origin publicly exposed or use -k to hide certificate errors.[3]
Check the Nginx configuration that actually handles uploads
Nginx's client_max_body_size limits the request body and is valid in http, server, and location contexts. Its documented default is 1m, although deployments can override it. Requests exceeding the configured limit receive 413. client_body_buffer_size is a different setting: it controls buffering, with larger bodies potentially written to temporary files. Increasing the buffer does not replace the body-size limit.[2]
Identify the server and location selected for the failing URL before editing an existing upload configuration. The following is one illustrative directive, not a complete replacement configuration:
# Place inside the confirmed upload location; assess the value for your workload. client_max_body_size 32m;
Preserve routing and security rules, back up the configuration, and keep the change scoped to the upload path. Setting this directive to 0 disables its size check; that is not a sensible blanket fix.[2]
For a systemd-managed deployment, validate the configuration before reloading:
sudo nginx -t && sudo systemctl reload nginx
Use the appropriate deployment procedure for containers or orchestration platforms. Restore the previous configuration if validation or rollout fails. Before increasing the limit, review temporary-storage capacity, concurrent uploads, timeouts, and cleanup behavior: accepting more data should not turn a predictable rejection into resource exhaustion.
Review application limits separately
Passing the reverse proxy does not guarantee that the application will accept the upload. Check the framework's request-body limit, the upload parser's per-file and multi-file limits, and business rules. A JSON-parser setting does not necessarily govern a multipart endpoint; locate the component that actually handles this route.
For PHP, review both upload_max_filesize and post_max_size. The first governs individual uploaded files; the second governs the total POST data and should be larger. Exceeding post_max_size can leave $_POST and $_FILES empty rather than produce the same 413 page.[4] Verify the configuration loaded by the web-serving process, not just the PHP CLI.
Keep an inventory for the CDN or edge, load balancer or gateway, reverse proxy, upload parser, and business endpoint. Record each limit's source and whether it can be changed. Raising an origin limit cannot bypass an unchangeable maximum elsewhere on the request path.
Separate HTTP chunked transfer from application-level chunked uploads
HTTP/1.1 chunked transfer coding sends a message body in transport chunks, but it is still one request.[5] Manually adding Transfer-Encoding: chunked is therefore not a reliable way around a request-body limit. Do not falsify Content-Length or send conflicting message-framing fields.
Application-level chunked uploads are different: the client sends several independent requests, identifies the upload session and chunk sequence, and relies on server-side validation and assembly. This requires an upload protocol supported by both sides. Splitting a file in browser code alone does not complete the implementation.
Before adopting it, define at least these safeguards:
Keep each chunk, including protocol overhead, below the effective limit across the upload path. Retain a separate total-file quota.
Bind upload sessions to the authenticated user. Handle duplicate chunks safely and prevent resumable uploads from replacing another user's data.
Validate chunk count, order, total size, and integrity before assembly.
Bound concurrency and clean up expired sessions and abandoned chunks.
If uploads move directly to object storage, use narrowly scoped, short-lived upload authorization. Check the storage service's size rules, cross-origin configuration, and completion validation. Preserve access controls when changing the upload entry point; permanently exposing the origin is not a shortcut.
Verify both successful uploads and intentional rejection
After the change, test a small valid file, a file close to the allowed maximum, an explicitly oversized file, a multi-file request, and interrupted-upload cleanup or resumption. Requests within policy should succeed; those exceeding policy should still fail with a useful message.
A new 504 response or storage error after raising the limit points to another bottleneck, not a completed fix. Record the configuration scope, rollback steps, and resource-monitoring checks before deployment.
The goal is to let legitimate uploads through while retaining size, authorization, and resource protections. Once you identify the rejecting layer, you can choose between a narrowly scoped limit change and a different upload protocol without blindly raising every limit.
Official references
Sources checked on October 10, 2026. Commands are illustrative and were not executed against the user's production upload endpoint.
[1] IETF RFC 9110, Section 15.5.14: 413 Content Too Large. https://www.rfc-editor.org/rfc/rfc9110.html
[2] Nginx Core Module: client_max_body_size and client_body_buffer_size. https://nginx.org/en/docs/http/ngx_http_core_module.html
[3] curl manual: --form, --resolve, --noproxy, and --write-out. https://curl.se/docs/manpage.html
[4] PHP core INI directives: post_max_size and upload_max_filesize. https://www.php.net/manual/en/ini.core.php
[5] IETF RFC 9112, Section 7.1: Chunked Transfer Coding. https://www.rfc-editor.org/rfc/rfc9112.html