{"record":{"id":"2e70ab59a0a30b8f","repo":"remix-run/remix","slug":"request-is-not-a-multipart-request","errorCode":null,"errorMessage":"Request is not a multipart request","messagePattern":"Request is not a multipart request","errorType":"validation","errorClass":"MultipartParseError","httpStatus":null,"severity":"error","filePath":"packages/multipart-parser/src/lib/multipart-request.ts","lineNumber":42,"sourceCode":"}\n\n/**\n * 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}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/multipart-parser/src/lib/multipart-request.ts#L24-L60","documentation":"parseMultipartRequest(request) validates the incoming web Request before parsing and throws MultipartParseError when its Content-Type is not multipart/form-data or multipart/mixed. This is a precondition failure: the parser only understands multipart bodies, so it refuses to proceed on JSON, urlencoded, or missing content types.","triggerScenarios":"Calling parseMultipartRequest with a Request whose Content-Type header is absent or is something like application/json or application/x-www-form-urlencoded; also requests forwarded/proxied with a rewritten Content-Type.","commonSituations":"A route handler that assumes every POST is multipart but receives fetch submissions with urlencoded bodies; HTML forms missing enctype=\"multipart/form-data\" when file upload is expected; test fixtures built with new Request(url, { body: JSON.stringify(...) }) without a multipart content type.","solutions":["Ensure client forms/requests send Content-Type: multipart/form-data with a boundary (e.g. <form enctype=\"multipart/form-form-data\"> or FormData via fetch, which sets it automatically)","Guard with isMultipartRequest(request) before calling parseMultipartRequest and handle non-multipart requests separately","Check middleware/proxies are not stripping or overriding the Content-Type header"],"exampleFix":"// before\nlet parts = parseMultipartRequest(request)\n\n// after\nimport { isMultipartRequest, parseMultipartRequest } from 'multipart-parser'\nif (!isMultipartRequest(request)) {\n  return new Response('Expected multipart request', { status: 415 })\n}\nlet parts = parseMultipartRequest(request)","handlingStrategy":"validation","validationCode":"import { isMultipartRequest } from 'multipart-parser'\n\nif (!isMultipartRequest(request)) {\n  return new Response('Unsupported media type', { status: 415 })\n}","typeGuard":"import { isMultipartRequest } from 'multipart-parser'\n// isMultipartRequest(request: Request): boolean — use as a predicate:\nfunction assertMultipart(request: Request): asserts request is Request {\n  if (!isMultipartRequest(request)) throw new Response('Unsupported', { status: 415 })\n}","tryCatchPattern":"try {\n  for await (let part of parseMultipartRequest(request)) { /* ... */ }\n} catch (error) {\n  if (error instanceof MultipartParseError && error.message.includes('not a multipart')) {\n    return new Response('Expected multipart/form-data', { status: 415 })\n  }\n  throw error\n}","preventionTips":["Always pair parseMultipartRequest with an isMultipartRequest check","Use <form enctype=\"multipart/form-data\"> for file uploads","Send FormData via fetch so content type is set correctly"],"tags":["multipart","content-type","http","request-validation"],"backgroundTag":"multipart-content-type-invalid","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}