{"record":{"id":"5931533ba23cc40d","repo":"remix-run/remix","slug":"invalid-content-type-header-missing-boundary-593153","errorCode":null,"errorMessage":"Invalid Content-Type header: missing boundary","messagePattern":"Invalid Content-Type header: missing boundary","errorType":"validation","errorClass":"MultipartParseError","httpStatus":null,"severity":"error","filePath":"packages/multipart-parser/src/lib/multipart.node.ts","lineNumber":79,"sourceCode":" * Parse a multipart Node.js request and yield each part as a {@link MultipartPart} object.\n *\n * @param req The Node.js `http.IncomingMessage` object containing multipart data\n * @param options Options for the parser, such as `maxHeaderSize`, `maxFileSize`, `maxParts`,\n * and `maxTotalSize`\n * @yields Parsed {@link MultipartPart} objects from the multipart request body\n * @returns An async generator yielding {@link MultipartPart} objects\n */\nexport async function* parseMultipartRequest(\n  req: http.IncomingMessage,\n  options?: MultipartParserOptions,\n): AsyncGenerator<MultipartPart, void, unknown> {\n  if (!isMultipartRequest(req)) {\n    throw new MultipartParseError('Request is not a multipart request')\n  }\n\n  let boundary = getMultipartBoundary(req.headers['content-type']!)\n  if (!boundary) {\n    throw new MultipartParseError('Invalid Content-Type header: missing boundary')\n  }\n\n  yield* parseMultipartStream(req, {\n    boundary,\n    maxHeaderSize: options?.maxHeaderSize,\n    maxFileSize: options?.maxFileSize,\n    maxParts: options?.maxParts,\n    maxTotalSize: options?.maxTotalSize,\n  })\n}\n","sourceCodeStart":61,"sourceCodeEnd":90,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/multipart-parser/src/lib/multipart.node.ts#L61-L90","documentation":"The Node parseMultipartRequest extracts the boundary from req.headers['content-type'] and throws MultipartParseError when the multipart content type has no boundary parameter. The boundary is mandatory metadata for splitting parts, so its absence is fatal.","triggerScenarios":"A raw Node request with Content-Type: multipart/form-data but no boundary=... — typically because a client or upstream proxy set the header manually or stripped the parameter.","commonSituations":"curl invocations with -H 'Content-Type: multipart/form-data' but using -d (urlencoded) instead of -F; proxies that rewrite content-type; misconfigured SDK uploads.","solutions":["Send multipart bodies with FormData / curl -F so the boundary is generated automatically","If setting the header manually, include the boundary and delimit the body with it","Log and inspect req.headers['content-type'] at the server edge to catch rewrites"],"exampleFix":"# before\ncurl -X POST http://localhost:3000/upload \\\n  -H 'Content-Type: multipart/form-data' \\\n  -d 'file=abc'\n\n# after\ncurl -X POST http://localhost:3000/upload \\\n  -F 'file=@./photo.png'","handlingStrategy":"validation","validationCode":"let contentType = String(req.headers['content-type'] ?? '')\nif (!/boundary=/i.test(contentType)) {\n  res.writeHead(400).end('Missing multipart boundary')\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  for await (let part of parseMultipartRequest(req)) { /* ... */ }\n} catch (error) {\n  if (error instanceof MultipartParseError && error.message.includes('missing boundary')) {\n    res.writeHead(400).end('Content-Type must include a boundary')\n    return\n  }\n  throw error\n}","preventionTips":["Never set multipart Content-Type by hand without the boundary","Log req.headers['content-type'] at the edge to catch proxy rewrites"],"tags":["multipart","node","boundary","content-type"],"backgroundTag":"multipart-boundary-missing","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}