A 413 from Nginx means the request body, usually a file upload, exceeded client_max_body_size. The default is only 1 MB, so this error tends to appear the first time a real user uploads a real file. The request is rejected before it ever reaches your application, which is why the app logs show nothing at all.
413 Request Entity Too Large
What this error means
Nginx enforces a maximum request body size as a protection against clients streaming huge payloads at your backend. When a request declares a Content-Length larger than client_max_body_size, Nginx answers 413 immediately and closes the exchange. The application never sees the request. The directive can be declared in the http, server, or location context, and the most specific context wins, so a value you raised in one place can be silently overridden in another.
The error also cascades through layers. Any proxy in the chain (a CDN, a cloud load balancer, a Kubernetes ingress, then your app framework) has its own body limit, and the smallest one in the chain decides.
Common causes
- The default 1 MB
client_max_body_sizewas never changed and a user uploaded something bigger. - The limit was raised at
httplevel but aserverorlocationblock sets a smaller value that takes precedence. - The fix was applied to the wrong vhost, or
nginx -s reloadwas never run after the edit. - Nginx is fine but another layer rejects the body: a Kubernetes ingress annotation, a CDN upload cap, or the framework limit inside the app (Express, Django, PHP
upload_max_filesize). - An API client sends an unexpectedly large JSON payload, not a file, and hits the same ceiling.
How to fix it
STABILIZE first. If uploads are a core user flow and they are all failing, raise the limit on the affected location to a value that covers your largest legitimate payload and reload Nginx. That restores service in one edit.
- Confirm Nginx is the layer rejecting the request. Send a body of known size straight at Nginx, bypassing any CDN.
dd if=/dev/zero of=/tmp/test-5mb.bin bs=1M count=5
curl -i -X POST --data-binary @/tmp/test-5mb.bin http://127.0.0.1/upload
- Find every place the limit is set, because the most specific one wins.
grep -rn "client_max_body_size" /etc/nginx/
DIAGNOSE from what you see. If Nginx returns 413 on the direct test, the grep output tells you which context is enforcing the small value. If the direct test succeeds but users still fail, the rejection is happening upstream of Nginx (CDN or load balancer) or downstream in the application framework, and you fix it there instead.
FIX by setting the limit in the narrowest scope that needs it, then validate and reload.
server {
# sane default for the whole vhost
client_max_body_size 2m;
location /upload {
# only the upload endpoint accepts large files
client_max_body_size 100m;
proxy_pass http://app;
proxy_request_buffering off;
}
}
nginx -t && nginx -s reload
proxy_request_buffering off streams the body to the upstream instead of buffering the whole file to disk first, which matters for large uploads. If you are on Kubernetes with ingress-nginx, the equivalent is the nginx.ingress.kubernetes.io/proxy-body-size: "100m" annotation on the Ingress resource. Remember to raise the matching limit in the application framework too, or the app will reject what Nginx now accepts.
How to prevent it
- Decide the real maximum upload size per endpoint and set it explicitly, scoped to the upload location, not globally.
- Keep body limits consistent across every layer: CDN, load balancer, ingress, Nginx, and the app framework.
- Add an upload of a realistic file size to your smoke tests so a config regression fails in CI, not in production.
- Return a friendly client-side message when a file exceeds the limit, checked in the browser before the upload starts.
- Avoid
client_max_body_size 0; an explicit ceiling protects the server from abusive payloads.
When to call a senior engineer
Call for help when uploads fail intermittently rather than always (which points at mismatched limits across multiple proxy layers or a CDN edge behaving differently per region), when large uploads succeed but exhaust disk through request buffering, or when you need genuinely large file ingestion and should move to direct-to-object-storage uploads with signed URLs instead of proxying gigabytes through Nginx. Erzon engineers can map the limit at every hop, fix the chain end to end, and design an upload path that scales past the proxy entirely.
Related errors we fix
Want a senior engineer to just fix it?
Paste this exact error into the form. A senior engineer replies within one business hour with what is likely wrong and a flat quote. Triage is free.
Book a fix