{"record":{"id":"94aa15b34713feac","repo":"vercel/next.js","slug":"invalid-body","errorCode":null,"errorMessage":"Invalid body","messagePattern":"Invalid body","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"error","filePath":"packages/next/src/server/api-utils/node/parse-body.ts","lineNumber":52,"sourceCode":"  try {\n    contentType = parse(req.headers['content-type'] || 'text/plain')\n  } catch {\n    contentType = parse('text/plain')\n  }\n  const { type, parameters } = contentType\n  const encoding = parameters.charset || 'utf-8'\n\n  let buffer\n\n  try {\n    const getRawBody =\n      require('next/dist/compiled/raw-body') as typeof import('next/dist/compiled/raw-body')\n    buffer = await getRawBody(req, { encoding, limit })\n  } catch (e) {\n    if (isError(e) && e.type === 'entity.too.large') {\n      throw new ApiError(413, `Body exceeded ${limit} limit`)\n    } else {\n      throw new ApiError(400, 'Invalid body')\n    }\n  }\n\n  const body = buffer.toString()\n\n  if (type === 'application/json' || type === 'application/ld+json') {\n    return parseJson(body)\n  } else if (type === 'application/x-www-form-urlencoded') {\n    const qs = require('querystring') as typeof import('querystring')\n    return qs.decode(body)\n  } else {\n    return body\n  }\n}\n","sourceCodeStart":34,"sourceCodeEnd":67,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/server/api-utils/node/parse-body.ts#L34-L67","documentation":"Thrown by parseBody() while reading the raw request body for an API route / Server Action. It is a 400 ApiError raised when getRawBody() rejects for any reason OTHER than the 'entity.too.large' size-limit error (which separately yields a 413). It signals the incoming request body could not be consumed at all -- malformed Content-Encoding, unsupported/invalid charset, a prematurely-closed/truncated stream, or a bad encoding parameter.","triggerScenarios":"A POST request hits an API route or Server Action handler that calls parseBody(req, limit). The Content-Type header carries a charset/encoding that raw-body rejects, the client sends a body with a content-encoding the server can't decode (e.g. gzip without decompression), or the connection drops mid-stream so getRawBody throws a non-size error. The catch at parse-body.ts:48 checks e.type === 'entity.too.large'; anything else falls through to this 400.","commonSituations":"A proxy/CDN injects or strips Content-Encoding causing the body to be unintelligible; a client posts an empty body with a charset like 'utf-32'; reverse-proxy timeouts truncate the upload; or a misconfigured fetch sets a wrong charset parameter. Also seen when the content-type header itself is unparseable (handled by the fallback at line 36-38) yet the body is still unreadable.","solutions":["Inspect the exact error cause: the raw-body error is re-thrown, so check server logs for the underlying message to determine if it's an encoding, charset, or stream issue.","Verify the client sends a valid Content-Type with a supported charset (e.g. 'application/json; charset=utf-8') and a consistent Content-Encoding.","If a reverse proxy or middleware is involved, confirm it is not truncating or double-encoding the request body.","Ensure the client is not closing the connection before the full body is transmitted (increase client-side timeout for large uploads)."],"exampleFix":"// before: client sends gzip body without server decompression\n// fetch(url, { body: gzip(json), headers: { 'content-encoding': 'gzip' } })\n\n// after: send uncompressed JSON or decompress in middleware\n// fetch(url, { body: json, headers: { 'content-type': 'application/json' } })","handlingStrategy":"validation","validationCode":"// Before calling parseBody, sanity-check the content-type/encoding.\n// parseBody itself reads content-type; validate upstream in middleware:\nexport function isValidBodyRequest(req) {\n  const ct = req.headers['content-type'] || ''\n  if (!ct) return false\n  const enc = req.headers['content-encoding']\n  // reject encodings you don't handle\n  if (enc && !['identity'].includes(enc.toLowerCase())) return false\n  return true\n}","typeGuard":"function isReadableBody(req): req is import('http').IncomingMessage & { readable: true } {\n  return Boolean(req && typeof (req as any).on === 'function' && (req as any).readable !== false)\n}","tryCatchPattern":"try {\n  const body = await parseBody(req, limit)\n} catch (e) {\n  if (e instanceof ApiError && e.statusCode === 400) {\n    res.status(400).json({ error: 'Malformed request body' })\n  } else if (e instanceof ApiError && e.statusCode === 413) {\n    res.status(413).json({ error: 'Body too large' })\n  } else {\n    throw e\n  }\n}","preventionTips":["Document and enforce a fixed Content-Type for each API route.","Reject or decompress unsupported Content-Encoding in middleware before parsing.","Cap request sizes at the proxy/load-balancer to fail fast.","Log the underlying raw-body error to distinguish encoding vs stream failures."],"tags":["api-routes","request-body","http","encoding"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}