Nginx — 413 Request Entity Too Large
Diagnose uploads rejected by Nginx with 413, align client_max_body_size across proxy and app, and return a clear JSON error without weakening limits.
Symptoms
- Nginx returns 413 Request Entity Too Large for an upload
- The request never reaches the application, so application logs show nothing
- Small files upload fine; files above roughly 1 MB fail
- The browser shows a generic error while the API expects JSON
Possible causes
- client_max_body_size is at its default of 1 MB or a value smaller than the upload
- A limit is set at http or server level but not in the matching location
- The application or upstream proxy has a different, smaller limit
- The client sends chunked or multipart data that the proxy buffers
- The request is routed through a CDN or ingress with its own body limit
Diagnosis steps
Reproduce and confirm which layer rejects the request
curl -v -F '[email protected]' https://example.com/api/uploadInterpretation
A 413 with an Nginx error page and no application request id means Nginx rejected it before proxying.
Inspect the effective Nginx configuration
nginx -T | grep -n 'client_max_body_size\|proxy_pass\|location'Interpretation
The dump shows the limit in effect for the matching server and location, including included files.
Compare with upstream and application limits
grep -R 'body.*limit\|max.*size' /etc/nginx /app/config 2>/dev/nullInterpretation
A CDN, ingress, or application limit may be smaller than Nginx even when Nginx is raised.
Root cause
A proxy in front of the application rejected the request body because it exceeded client_max_body_size before the application could handle it. The effective limit depends on the matching location and any upstream layers.
Fix
Set an explicit client_max_body_size for the upload location only, align the application and upstream limits, and return a JSON error for API clients. Keep the limit as small as the product requires rather than raising it globally.
Risk note
A global 1 GB limit increases the impact of unauthenticated upload abuse. Pair a larger limit with authentication, rate limiting, streaming to disk, and server-side size enforcement.
Verify the fix
Upload a file below and above the limit, confirm the boundary behavior, and check that the application receives the request and rejects oversized bodies with the expected status. Verify the error page content type for API routes.
413 comes from the proxy, not the app
When Nginx rejects a body, the request never reaches the application. Application logs are empty, and the response is an Nginx HTML error page rather than the API’s JSON shape. The default client_max_body_size is 1 MB, which explains why small uploads succeed and larger ones fail.
location /api/upload {
client_max_body_size 10m;
proxy_pass http://app;
proxy_request_buffering off;
}
Set the limit on the upload location, not globally, so unrelated endpoints stay protected. If a CDN or ingress sits in front, its limit must be aligned too.
Align every layer
The effective limit is the smallest limit in the request path. Check the ingress, Nginx, the application framework, and any object-storage policy. A 10 MB limit in Nginx with a 5 MB application limit still rejects at 5 MB, but the error and logs come from a different layer.
Return a useful error
API clients need a parseable response. Use error_page 413 = @json_413; and return JSON with a request id. Do not return a generic HTML page that the client tries to parse as JSON. Log the rejection with the content length and route, but not the body.
Keep limits safe
A larger upload limit increases exposure to unauthenticated abuse. Require authentication for uploads, rate-limit them, stream large bodies to disk, and enforce the size again in the application. Test the exact boundary: a file at the limit should pass and one byte over should fail with the expected status.
Fix and verify
Fix the effective limit by setting client_max_body_size on the upload location, aligning the ingress and application limits, and adding a JSON error page for API routes. Verify with a file just below the limit and one just above it, confirming that the application receives the allowed request and the oversized request returns the intended status and content type. Check the Nginx access log for the request id to prove which layer rejected it.