{"record":{"id":"5098eb305bae3967","repo":"remix-run/remix","slug":"request-body-is-empty","errorCode":null,"errorMessage":"Request body is empty","messagePattern":"Request body is empty","errorType":"validation","errorClass":"MultipartParseError","httpStatus":null,"severity":"error","filePath":"packages/multipart-parser/src/lib/multipart-request.ts","lineNumber":45,"sourceCode":" * Parse a multipart [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)\n * and yield each part as a {@link MultipartPart} object. Useful in HTTP server contexts\n * for handling incoming `multipart/*` requests.\n *\n * @param request The `Request` object containing multipart data\n * @param options Optional parser options, such as `maxHeaderSize`, `maxFileSize`, `maxParts`,\n * and `maxTotalSize`\n * @yields Parsed {@link MultipartPart} objects from the request body\n * @returns An async generator yielding {@link MultipartPart} objects\n */\nexport async function* parseMultipartRequest(\n  request: Request,\n  options?: MultipartParserOptions,\n): AsyncGenerator<MultipartPart, void, unknown> {\n  if (!isMultipartRequest(request)) {\n    throw new MultipartParseError('Request is not a multipart request')\n  }\n  if (!request.body) {\n    throw new MultipartParseError('Request body is empty')\n  }\n\n  let boundary = getMultipartBoundary(request.headers.get('Content-Type')!)\n  if (!boundary) {\n    throw new MultipartParseError('Invalid Content-Type header: missing boundary')\n  }\n\n  yield* parseMultipartStream(request.body, {\n    boundary,\n    maxHeaderSize: options?.maxHeaderSize,\n    maxFileSize: options?.maxFileSize,\n    maxParts: options?.maxParts,\n    maxTotalSize: options?.maxTotalSize,\n  })\n}\n","sourceCodeStart":27,"sourceCodeEnd":61,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/multipart-parser/src/lib/multipart-request.ts#L27-L61","documentation":"parseMultipartRequest throws MultipartParseError('Request body is empty') when the Request has a null/absent body. Even a correctly-typed multipart request must carry a body stream for the parser to consume, so an empty body is rejected up front rather than producing a confusing parse failure later.","triggerScenarios":"Calling parseMultipartRequest on a Request constructed with no body (or body: null), a GET/HEAD request, or a body already consumed or cancelled by earlier middleware/handler code.","commonSituations":"Requests whose stream was already read by another parser (e.g. await request.formData() earlier in the handler), hand-constructed Request objects in tests without a body, or intermediaries that buffer and drop the body.","solutions":["Check request.body is non-null before parsing","Avoid consuming the body twice — remove prior request.formData()/request.text() calls or clone the request first","Ensure clients actually send a multipart body even for empty forms (FormData with at least one field)"],"exampleFix":"// before\nlet parts = parseMultipartRequest(request) // body already consumed\n\n// after\nif (!request.body) {\n  return new Response('Empty body', { status: 400 })\n}\nlet parts = parseMultipartRequest(request.clone()) // preserve original for later reads","handlingStrategy":"validation","validationCode":"if (request.method !== 'POST' && request.method !== 'PUT') {\n  return new Response('Method not allowed', { status: 405 })\n}\nif (!request.body) {\n  return new Response('Empty body', { status: 400 })\n}","typeGuard":null,"tryCatchPattern":"try {\n  for await (let part of parseMultipartRequest(request)) { /* ... */ }\n} catch (error) {\n  if (error instanceof MultipartParseError && error.message === 'Request body is empty') {\n    return new Response('Empty request body', { status: 400 })\n  }\n  throw error\n}","preventionTips":["Never read request.body/formData before multipart parsing; clone first if you must","Reject bodyless methods (GET/HEAD) at the route level before parsing"],"tags":["multipart","request-body","http"],"backgroundTag":"empty-request-body","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}