Express PayloadTooLargeError — Request Body Over Limit
Resolve Express body-parser 413 Entity Too Large errors by matching the JSON and urlencoded limits to real payload sizes instead of blindly raising them.
Symptoms
- The API returns 413 with "request entity too large" only for big submissions
- Small JSON succeeds while a slightly larger object returns 413
- The error surfaces from body-parser, not from your route handler
Possible causes
- The default JSON limit of 100kb is smaller than the request being sent
- A reverse proxy also caps body size and returns 413 before Express sees it
- A multipart or large text payload is routed through the JSON parser
Diagnosis steps
Confirm which component rejects the body
curl -i -X POST https://api.example.com/items -H 'Content-Type: application/json' --data-binary @large.jsonInterpretation
If the 413 comes with the proxy Server header it is the proxy; if body-parser logs it, it is the app limit.
Measure the actual payload size
wc -c large.jsonInterpretation
Compare against the configured limit. Set the limit a little above the real maximum rather than to unlimited.
Inspect parser configuration
grep -rn "bodyParser\|express.json" src/ | grep -i limitInterpretation
The configured limit (or its absence, meaning the 100kb default) explains the threshold.
Root cause
body-parser rejects a request as soon as the streamed body exceeds its configured limit, raising PayloadTooLargeError before your handler runs. Any proxy in front may impose a second, often smaller, cap.
Fix
Set an explicit, bounded limit on each parser (for example express.json({ limit: "1mb" })), route large uploads through a streaming/multipart handler instead of the JSON parser, and align the proxy client_max_body_size to the same value.
Risk note
An unlimited body limit is a denial-of-service vector; always bound it and validate Content-Length.
Verify the fix
Post a payload just under the new limit and confirm 200, then post one just over it and confirm a controlled 413 with a helpful message rather than a crash.
Symptoms
This guide profiles the failure behind “Express PayloadTooLargeError — Request Body Over Limit”. It walks through the observable symptoms, a reproducible diagnosis path, the underlying root cause, the concrete fix, and how to verify the change and prevent a regression.
Observed symptoms include:
- The API returns 413 with “request entity too large” only for big submissions
- Small JSON succeeds while a slightly larger object returns 413
- The error surfaces from body-parser, not from your route handler
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Confirm which component rejects the body
curl -i -X POST https://api.example.com/items -H 'Content-Type: application/json' --data-binary @large.json
If the 413 comes with the proxy Server header it is the proxy; if body-parser logs it, it is the app limit.
Step 2: Measure the actual payload size
wc -c large.json
Compare against the configured limit. Set the limit a little above the real maximum rather than to unlimited.
Step 3: Inspect parser configuration
grep -rn "bodyParser\|express.json" src/ | grep -i limit
The configured limit (or its absence, meaning the 100kb default) explains the threshold.
Likely contributors, in order of frequency:
- The default JSON limit of 100kb is smaller than the request being sent
- A reverse proxy also caps body size and returns 413 before Express sees it
- A multipart or large text payload is routed through the JSON parser
Root Cause
body-parser rejects a request as soon as the streamed body exceeds its configured limit, raising PayloadTooLargeError before your handler runs. Any proxy in front may impose a second, often smaller, cap.
The Fix
Set an explicit, bounded limit on each parser (for example express.json({ limit: “1mb” })), route large uploads through a streaming/multipart handler instead of the JSON parser, and align the proxy client_max_body_size to the same value.
Watch out: An unlimited body limit is a denial-of-service vector; always bound it and validate Content-Length.
import express from 'express';
const app = express();
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
// 413 arrives before this handler when the limit is exceeded.
app.post('/items', (req, res) => res.json({ received: req.body }));
app.use((err, _req, res, _next) => {
if (err.type === 'entity.too.large') return res.status(413).json({ error: 'payload too large' });
res.status(500).json({ error: 'internal error' });
});
Verify and Prevent
Post a payload just under the new limit and confirm 200, then post one just over it and confirm a controlled 413 with a helpful message rather than a crash.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.