# nginx 413: Request Entity Too Large on upload
nginx refused the request body because it exceeded client_max_body_size, which defaults to just 1 MB. The trap is that several layers can each impose their own limit, and raising it in the application changes nothing when the proxy in front rejects the body first.
| Error | 413 Request Entity Too Large |
|---|---|
| Applies to | nginx all versions · ingress-nginx all versions |
| Primary cause | client_max_body_size is at its default of 1 MB |
| First check | grep 'too large body' /var/log/nginx/error.log | tail -5 |
| Confidence | medium2 sources, 2 primary |
| Verified | 2026-08-08fresh0d old · recheck by 2027-08-08 |
| Domain | networkingnginx http-413 uploads reverse-proxy configuration ingress |
## Error
413 Request Entity Too LargeCodes: 413
Also seen as: 413 Content Too Large · Payload Too Large · client intended to send too large body · 413 Request Entity Too Large nginx
## Problem
File uploads fail above a certain size while smaller ones succeed. The application never sees the request, so its own logs are silent and its upload limit appears to be ignored. Raising the framework's limit has no effect, which makes the boundary look arbitrary — it is nginx rejecting the body before anything downstream is involved.
## Root Cause5 known causes, ranked
- 01
client_max_body_size is at its default of 1 MB
primarynginx caps request bodies at one megabyte unless told otherwise. Most people never set the directive, so the first upload over that size fails on a stock configuration.
→ how to tell: The nginx error log records 'client intended to send too large body' with the exact byte count, and the boundary sits at 1048576 bytes
- 02
The directive is set in the wrong context
primaryclient_max_body_size applies in http, server and location blocks, and the most specific match wins. A generous value in http is overridden by a stale small one in the location that actually handles uploads.
→ how to tell: nginx -T shows the directive more than once, with a smaller value in the block matching the upload path
- 03
Another proxy layer in front imposes its own limit
commonA CDN, load balancer or ingress controller rejects the body before nginx sees it. The response looks identical, so fixing nginx changes nothing.
→ how to tell: curl against the origin accepts the upload while the same request to the public hostname fails, and nginx's own error log has no matching entry
- 04
The Kubernetes ingress annotation is missing
commonAn ingress-nginx controller generates its configuration from annotations, so editing nginx.conf inside the pod is overwritten. The limit has to be declared on the Ingress object.
→ how to tell: The rejection comes from an ingress-nginx pod and no proxy-body-size annotation is present on the Ingress
- 05
The application also has a limit, reached after nginx is fixed
edgeRaising nginx's limit moves the failure downstream rather than removing it. The framework then rejects the body with its own error, which is easy to mistake for the fix not working.
→ how to tell: The status code changes from 413 to a framework-specific error, or the message now names the application rather than nginx
## Solution
- 01Confirm which layer is rejecting the request. nginx logs the intended body size when it refuses, so its absence tells you the rejection happened upstream.
$ grep 'too large body' /var/log/nginx/error.log | tail -5 - 02Print the configuration nginx has actually loaded, including every include, and look for competing definitions rather than assuming the file you edited is the one in force.
$ nginx -T 2>/dev/null | grep -n 'client_max_body_size' - 03Set the limit in the block that handles uploads, and keep it consistent with any outer value so the specific one is not accidentally smaller.nginx
http { client_max_body_size 50m; # sensible ceiling for the whole server server { location /api/upload { client_max_body_size 200m; # larger only where genuinely needed proxy_pass http://app; } } }note: A value of 0 disables the check entirely. That turns a bounded rejection into an unbounded one, so prefer a real ceiling over removing it.
- 04Reload rather than restart, after testing the configuration parses.
$ nginx -t && nginx -s reload - 05On Kubernetes, set it on the Ingress. Editing the controller's generated config is undone on the next reconcile.yaml
metadata: annotations: nginx.ingress.kubernetes.io/proxy-body-size: "200m" - 06Raise the application's own limit to match, and expect the failure to reappear there once nginx stops rejecting. Both layers have to agree.javascript
// Express app.use(express.json({ limit: "200mb" })); // PHP — php.ini // upload_max_filesize = 200M // post_max_size = 200M
verify · An upload just under the new limit succeeds end to end, one just over it is rejected with 413 by the layer you configured, and the nginx error log names the expected boundary rather than 1048576.
if that fails · For genuinely large files, stop proxying the body at all: issue a pre-signed URL and have the client upload directly to object storage. That removes the limit question from every layer instead of raising it in each.
## Applies To
- nginx
- all versions— client_max_body_size defaults to 1m and applies in http, server and location contexts.
- ingress-nginx
- all versions— Configured through the proxy-body-size annotation rather than nginx.conf.
- Platforms
- linux
## Not Applicable Tonear misses this page does not answer
- ✗ 408 Request Timeout, where the body is slow rather than large
- ✗ 431 Request Header Fields Too Large, which concerns headers and is governed by different directives
- ✗ Application-level upload limits that return the framework's own error rather than 413 from nginx
- ✗ Apache's LimitRequestBody, which produces the same status from an unrelated configuration
## Evidence2 sources
https://nginx.org/en/docs/http/ngx_http_core_module.html
nginx · read 2026-08-08
supports: That client_max_body_size governs the maximum request body, defaults to 1m, and is valid in http, server and location contexts — which is what makes the wrong-context case possible.
“Sets the maximum allowed size of the client request body.”
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/413
MDN Web Docs · read 2026-08-08
supports: That 413 means the request entity exceeded a server-defined limit — so any layer in the chain may legitimately emit it, which is why identifying the layer comes before changing configuration.
“indicates that the request entity was larger than limits defined by server”
## Confidence
mediumThe directive's meaning, its 1m default and its valid contexts are quoted from nginx's own module reference, and the status semantics from MDN. Confidence is medium rather than high because it rests on two sources: the ingress annotation name and the framework-side limits are drawn from the respective projects' conventions rather than quoted here, and the layer-identification method is diagnostic practice.