remix-run/remix · error · MultipartParseError

Invalid Content-Type header: missing boundary

Error message

Invalid Content-Type header: missing boundary

What it means

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.

Source

Thrown at packages/multipart-parser/src/lib/multipart.node.ts:79

 * Parse a multipart Node.js request and yield each part as a {@link MultipartPart} object.
 *
 * @param req The Node.js `http.IncomingMessage` object containing multipart data
 * @param options Options for the parser, such as `maxHeaderSize`, `maxFileSize`, `maxParts`,
 * and `maxTotalSize`
 * @yields Parsed {@link MultipartPart} objects from the multipart request body
 * @returns An async generator yielding {@link MultipartPart} objects
 */
export async function* parseMultipartRequest(
  req: http.IncomingMessage,
  options?: MultipartParserOptions,
): AsyncGenerator<MultipartPart, void, unknown> {
  if (!isMultipartRequest(req)) {
    throw new MultipartParseError('Request is not a multipart request')
  }

  let boundary = getMultipartBoundary(req.headers['content-type']!)
  if (!boundary) {
    throw new MultipartParseError('Invalid Content-Type header: missing boundary')
  }

  yield* parseMultipartStream(req, {
    boundary,
    maxHeaderSize: options?.maxHeaderSize,
    maxFileSize: options?.maxFileSize,
    maxParts: options?.maxParts,
    maxTotalSize: options?.maxTotalSize,
  })
}

View on GitHub (pinned to 9696913134)

Solutions

  1. Send multipart bodies with FormData / curl -F so the boundary is generated automatically
  2. If setting the header manually, include the boundary and delimit the body with it
  3. Log and inspect req.headers['content-type'] at the server edge to catch rewrites

Example fix

# before
curl -X POST http://localhost:3000/upload \
  -H 'Content-Type: multipart/form-data' \
  -d 'file=abc'

# after
curl -X POST http://localhost:3000/upload \
  -F 'file=@./photo.png'
Defensive patterns

Strategy: validation

Validate before calling

let contentType = String(req.headers['content-type'] ?? '')
if (!/boundary=/i.test(contentType)) {
  res.writeHead(400).end('Missing multipart boundary')
  return
}

Try / catch

try {
  for await (let part of parseMultipartRequest(req)) { /* ... */ }
} catch (error) {
  if (error instanceof MultipartParseError && error.message.includes('missing boundary')) {
    res.writeHead(400).end('Content-Type must include a boundary')
    return
  }
  throw error
}

Prevention

When it happens

Trigger: 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.

Common situations: curl invocations with -H 'Content-Type: multipart/form-data' but using -d (urlencoded) instead of -F; proxies that rewrite content-type; misconfigured SDK uploads.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/5931533ba23cc40d. Report an issue: GitHub.