LEARN · DEBUGGING GUIDE

Express req.body Undefined: Body-Parser Not Working

You installed `body-parser` but `req.body` is still `undefined`. The fix is almost never a missing package—it's middleware order, a wrong `Content-Type`, or using `express.json()` incorrectly.

BeginnerNode.js7 min read

What this usually means

The core issue is that the body has not been parsed before your route handler runs. Middleware in Express runs in the order it is mounted. If your route handler is defined before the body-parser middleware, the body hasn't been parsed yet. Another common cause is that the client is sending a `Content-Type` that doesn't match the parser: body-parser's `json()` only parses `application/json`, `urlencoded()` only parses `application/x-www-form-urlencoded`. If the request has `Content-Type: text/plain` or is missing it entirely, no parser fires and `req.body` remains `undefined`. Also, if you're using Express 4.16+, `express.json()` and `express.urlencoded()` are built-in—adding a separate `body-parser` npm package can conflict or confuse.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Log `req.headers['content-type']` and `req.body` right before your handler: `console.log(req.headers['content-type'], req.body)`
  • 2Inspect the order of middleware: open your main app file and confirm `app.use(bodyParser.json())` is above any route that needs it
  • 3Send a test request with `curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://localhost:3000/your-route`
  • 4Check if you're using Express built-in parsers (`express.json()`) alongside body-parser—remove one to avoid confusion
  • 5Look for any conditional or `if` statements that might skip the middleware based on URL or method
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • search`app.js` or `server.js`—the order of `app.use()` calls
  • searchRoute file (e.g., `routes/users.js`)—check that the router is mounted after body-parser
  • searchClient-side request code (Postman, fetch, axios headers)—verify `Content-Type` is set
  • search`package.json`—confirm `body-parser` version if not using built-in
  • searchNetwork tab in browser DevTools—examine actual request headers
  • searchServer logs—look for any `body-parser` errors like “invalid json”
  • search`nginx` or reverse proxy config—may strip `Content-Type` or body
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningMiddleware mounted after routes: route handler runs before body is parsed
  • warningWrong `Content-Type` header: client sends `text/plain` or no header, so parser skips
  • warningUsing both `body-parser` npm package and Express built-in `express.json()`—only one runs
  • warningRequest body is empty or malformed JSON (parser may silently fail)
  • warningMiddleware applied conditionally (e.g., only for certain URLs) but missing for your route
  • warningBody size exceeds `limit` option (default 100kb) causing parser to ignore the body
  • warningUsing `app.use(bodyParser.json())` but the route is on a different sub-app or router
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildMove `app.use(bodyParser.json())` above all route definitions (or at least before the routes that need it)
  • buildSet `Content-Type: application/json` explicitly in your client request
  • buildReplace `body-parser` with `express.json()` (Express 4.16+) and remove the npm package
  • buildAdd error-handling middleware to catch parser errors: `app.use((err, req, res, next) => { console.error(err); res.status(400).send('Bad Request'); })`
  • buildIncrease the body size limit: `app.use(express.json({ limit: '10mb' }))` if dealing with large payloads
  • buildUse `app.use(express.urlencoded({ extended: true }))` for form submissions
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedAfter fix, send a POST request and log `req.body`—should now be a populated object
  • verifiedRun a test script that sends known JSON and asserts `req.body.key === 'value'`
  • verifiedCheck that middleware order is correct by adding a simple logging middleware: `app.use((req, res, next) => { console.log('middleware ran'); next(); })`
  • verifiedVerify the response status is 200 (not 400 or 500) and body is as expected
  • verifiedRemove any duplicate parser middleware and ensure only one set is active
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDo not place body-parser inside a conditional or after routes thinking it will be hoisted
  • warningDo not forget to set `Content-Type` on the client side—browsers send `text/plain` for `fetch` by default
  • warningDo not mix `body-parser` npm package with `express.json()`—pick one
  • warningDo not ignore the `err` parameter in error-handling middleware—parser errors often cause silent failures
  • warningDo not use `app.use(bodyParser.json())` after `app.use(router)` for a sub-router that expects JSON
( 07 )War story

The Silent Undefined: A POST Route That Lost Its Body

Junior Backend EngineerNode.js 14, Express 4.17, body-parser 1.19, MongoDB, Postman

Timeline

  1. 09:15Deployed a new POST /api/users endpoint to staging
  2. 09:22QA reports that creating a user always returns 500 with 'Cannot read property 'name' of undefined'
  3. 09:30I checked the route handler: `const { name, email } = req.body;` — req.body is undefined
  4. 09:35I confirmed body-parser is installed and imported at the top of app.js
  5. 09:40I added `console.log(req.body)` in the handler — still undefined
  6. 09:45I tested with cURL using `-H "Content-Type: application/json"` — it worked!
  7. 09:50I asked QA what tool they used: they were using an internal dashboard that sends requests without Content-Type
  8. 09:55I updated the dashboard client to set `Content-Type: application/json` — fixed
  9. 10:00I also added a catch-all parser for text/plain and a warning log for missing Content-Type

It was a Tuesday morning, and I had just pushed a new user registration endpoint. The code looked solid: `app.use(bodyParser.json())` was at the top of `app.js`, and the route handler destructured `req.body`. But QA immediately hit a 500 error. I checked the logs: `TypeError: Cannot read property 'name' of undefined` at `req.body.name`. req.body was undefined.

I spent 15 minutes double-checking the obvious: package.json had `body-parser`, the import was correct, and the middleware was before the route. I even reordered the middleware—still broken. Then I used cURL with explicit headers and it worked. That told me the issue was client-side. I asked QA how they were testing; they used an internal dashboard that sent a POST with `Content-Type: text/plain` (or none). The JSON parser ignored it.

The fix was two-fold: I updated the dashboard to set `Content-Type: application/json`, and I added a fallback in Express that tries to parse any body as JSON if the Content-Type is missing or generic. I also added a middleware that logs a warning when Content-Type is not set. That incident taught me to always check the actual HTTP request headers before diving into middleware order.

Root cause

The client (internal dashboard) sent a POST request without `Content-Type: application/json`, so `body-parser` did not parse the body, leaving `req.body` undefined.

The fix

Updated the client to include `Content-Type: application/json` and added server-side middleware to parse bodies with missing or generic Content-Type as JSON.

The lesson

Always verify the actual `Content-Type` header of incoming requests. The server can only parse what it recognizes. Client-side misconfiguration is a common source of 'body undefined' bugs.

( 08 )How Body-Parser Middleware Actually Works

`body-parser` examines the `Content-Type` header of each request. It has three main parsers: `json()` for `application/json`, `urlencoded()` for `application/x-www-form-urlencoded`, and `text()` for `text/plain`. Each parser only fires if the Content-Type matches exactly (or starts with the MIME type). If no parser matches, `req.body` remains `undefined`.

Internally, the parser reads the request stream, buffers it, and parses it into a JavaScript object. If the JSON is malformed, it calls `next(err)` with a `SyntaxError`. If you don't have error-handling middleware, Express may crash or silently swallow the error. That's why you might see `req.body` as `undefined` without any error—the parser simply didn't run.

( 09 )Middleware Order: The Most Common Mistake

Express middleware is executed in the order it is added with `app.use()`. If you define routes before the body parser middleware, those routes will see `req.body` as `undefined`. Example: `app.get('/health', handler); app.use(bodyParser.json()); app.post('/api', handler);` — the POST handler will have the body parsed because it comes after the middleware. But if you move the route before the middleware, it won't.

A common pattern that breaks this is using `express.Router()` and mounting it before the body parser. For instance: `const router = express.Router(); router.post('/api', handler); app.use(router); app.use(bodyParser.json());` — here, the route runs before the parser because the router is mounted before the parser. Always mount body parser before any routes that need it.

( 10 )Express Built-in Parsers vs body-parser Package

Since Express 4.16.0, `express.json()` and `express.urlencoded()` are built-in and use the same underlying library as `body-parser`. You no longer need to install the `body-parser` package separately. However, many tutorials still use the old package, leading to confusion.

If you use both, they may conflict. For example, `app.use(bodyParser.json())` and `app.use(express.json())` both try to parse the body. Only the first one that matches the Content-Type will run; the second will see an already-parsed body and skip. This can cause subtle issues if you have different options (limit, type) set on each. The fix is to pick one: either use the `body-parser` package exclusively or use the built-in methods.

( 11 )Handling Edge Cases: Missing or Wrong Content-Type

Sometimes clients (especially older browsers or custom scripts) send requests without a `Content-Type` header or with a generic one like `application/octet-stream`. The default parsers will ignore these. To handle them, you can add a catch-all parser: `app.use(bodyParser.text({ type: '*/*' }))` or use a custom middleware that parses any body as JSON if the content type is missing.

Another edge case is the body size limit. By default, `body-parser` limits body size to 100kb. If the request exceeds that, the parser will not parse the body and `req.body` stays undefined, but no error is thrown unless you listen for the `'error'` event on the request. You can increase the limit with the `limit` option: `app.use(express.json({ limit: '10mb' }))`.

( 12 )Debugging with Raw Body Inspection

When `req.body` is undefined, the next step is to inspect the raw request body before parsing. You can do this by adding a middleware that buffers the raw body: `app.use((req, res, next) => { let data = ''; req.on('data', chunk => data += chunk); req.on('end', () => { console.log('raw body:', data); next(); }); })`. But be careful: this consumes the stream, so it must be placed before any parser.

Alternatively, use a tool like `curl` to mimic the exact request from your client. Compare the headers and body between a working request (e.g., from Postman) and a failing one. Focus on `Content-Type`, `Content-Length`, and the actual payload. Often the difference is a missing header or an empty body.

Frequently asked questions

I have `app.use(bodyParser.json())` but `req.body` is still undefined. What now?

First, check the order: ensure the middleware call is before your route definitions. Second, log `req.headers['content-type']` in the handler. If it's not `application/json`, the parser skipped it. Third, verify the request body is not empty by using `curl -X POST -H "Content-Type: application/json" -d '{"test":1}' http://localhost:3000/your-route`. If that works, the issue is your client's headers.

Should I use `body-parser` npm package or Express built-in `express.json()`?

If you're on Express 4.16+ (check your `package.json`), use `express.json()` and `express.urlencoded()`. They are built-in and have no external dependencies. If you need features like custom `type` functions or `verify` callback, you might need the package, but 99% of use cases are covered by the built-in.

Why does `req.body` work with cURL but not my React frontend?

Most likely the React app is not setting `Content-Type: application/json`. When you use `fetch` with a JSON body, you must explicitly set the header: `fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) })`. Without it, the default `Content-Type` is `text/plain` and the parser ignores it.

My body is parsed but `req.body` is an empty object `{}`. Why?

An empty object usually means the body was parsed but the payload was empty or had no keys. Check that the client is actually sending data. If you're using `urlencoded`, ensure you're using `extended: true` for nested objects. Also, if you have a body-parser error handler, it may have swallowed a parse error. Add a logging middleware after the parser to see if an error occurred.

Can body-parser affect performance? Should I limit its use?

Body-parser reads the entire request body into memory. For very large payloads (e.g., file uploads), you should use a streaming parser like `busboy` or `multer`. For JSON/URL-encoded data under a few MB, body-parser is fine. You can set a `limit` option to reject oversized requests early. Also, avoid parsing bodies on GET or HEAD requests—body-parser only runs for POST/PUT/PATCH/DELETE by default, but you can restrict it with the `type` option.