remix-run/remix · error · MultipartParseError
Request is not a multipart request
Error message
Request is not a multipart request
What it means
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.
Source
Thrown at packages/multipart-parser/src/lib/multipart-request.ts:42
}
/**
* Parse a multipart [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
* and yield each part as a {@link MultipartPart} object. Useful in HTTP server contexts
* for handling incoming `multipart/*` requests.
*
* @param request The `Request` object containing multipart data
* @param options Optional parser options, such as `maxHeaderSize`, `maxFileSize`, `maxParts`,
* and `maxTotalSize`
* @yields Parsed {@link MultipartPart} objects from the request body
* @returns An async generator yielding {@link MultipartPart} objects
*/
export async function* parseMultipartRequest(
request: Request,
options?: MultipartParserOptions,
): AsyncGenerator<MultipartPart, void, unknown> {
if (!isMultipartRequest(request)) {
throw new MultipartParseError('Request is not a multipart request')
}
if (!request.body) {
throw new MultipartParseError('Request body is empty')
}
let boundary = getMultipartBoundary(request.headers.get('Content-Type')!)
if (!boundary) {
throw new MultipartParseError('Invalid Content-Type header: missing boundary')
}
yield* parseMultipartStream(request.body, {
boundary,
maxHeaderSize: options?.maxHeaderSize,
maxFileSize: options?.maxFileSize,
maxParts: options?.maxParts,
maxTotalSize: options?.maxTotalSize,
})
}View on GitHub (pinned to 9696913134)
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
Example fix
// before
let parts = parseMultipartRequest(request)
// after
import { isMultipartRequest, parseMultipartRequest } from 'multipart-parser'
if (!isMultipartRequest(request)) {
return new Response('Expected multipart request', { status: 415 })
}
let parts = parseMultipartRequest(request) Defensive patterns
Strategy: validation
Validate before calling
import { isMultipartRequest } from 'multipart-parser'
if (!isMultipartRequest(request)) {
return new Response('Unsupported media type', { status: 415 })
} Type guard
import { isMultipartRequest } from 'multipart-parser'
// isMultipartRequest(request: Request): boolean — use as a predicate:
function assertMultipart(request: Request): asserts request is Request {
if (!isMultipartRequest(request)) throw new Response('Unsupported', { status: 415 })
} Try / catch
try {
for await (let part of parseMultipartRequest(request)) { /* ... */ }
} catch (error) {
if (error instanceof MultipartParseError && error.message.includes('not a multipart')) {
return new Response('Expected multipart/form-data', { status: 415 })
}
throw error
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid Content-Type header: missing boundary
- Request is not a multipart request
- Request body is empty
- Invalid Content-Type header: missing boundary
- Multipart boundary exceeds maximum length of ${maxBoundaryLe
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/2e70ab59a0a30b8f.
Report an issue: GitHub.