remix-run/remix · error · MaxHeaderSizeExceededError
Exceeded maximum header size
Error message
Exceeded maximum header size
What it means
While scanning for the \r\n\r\n that terminates a part's headers, the parser buffers the pending bytes; if the buffered header region grows beyond maxHeaderSize without finding the double newline, it throws MaxHeaderSizeExceededError. This guards against unbounded memory use from header-flood or malformed parts.
Source
Thrown at packages/multipart-parser/src/lib/multipart.ts:401
break
}
index += 2 // Skip \r\n after boundary
this.#state = MultipartParserStateHeader
}
if (this.#state === MultipartParserStateHeader) {
if (chunkLength - index < 4) {
this.#buffer = chunk.subarray(index)
break
}
let headerEndIndex = findDoubleNewline(chunk, index)
if (headerEndIndex === -1) {
if (chunkLength - index > this.maxHeaderSize) {
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
}
this.#buffer = chunk.subarray(index)
break
}
if (headerEndIndex - index > this.maxHeaderSize) {
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
}
this.#currentHeader = chunk.subarray(index, headerEndIndex)
this.#currentContent = []
this.#contentLength = 0
index = headerEndIndex + 4 // Skip header + \r\n\r\n
this.#state = MultipartParserStateBody
View on GitHub (pinned to 9696913134)
Solutions
- If headers are legitimately large, pass a larger maxHeaderSize in MultipartParserOptions (default 8 KB)
- Audit clients for unnecessary per-part headers and trim them
- If unexpected, verify the boundary matches the actual body delimiters — a mismatch makes body data parse as headers
Example fix
// before
let parts = parseMultipartRequest(request) // default 8KB header limit
// after
let parts = parseMultipartRequest(request, { maxHeaderSize: 64 * 1024 }) Defensive patterns
Strategy: validation
Validate before calling
// pre-check declared header size when possible
let declared = Number(request.headers.get('Content-Length') ?? 0)
if (declared > 10 * 1024 * 1024) return new Response('Payload too large', { status: 413 })
// and parse with an explicit, adequate limit:
parseMultipartRequest(request, { maxHeaderSize: 64 * 1024 }) Try / catch
try {
for await (let part of parseMultipartRequest(request)) { /* ... */ }
} catch (error) {
if (error instanceof MaxHeaderSizeExceededError) {
return new Response('Part headers too large', { status: 413 })
}
throw error
} Prevention
- Configure maxHeaderSize to match your clients' real per-part headers
- Discourage per-part metadata headers; move metadata into body fields
When it happens
Trigger: A multipart part whose headers never contain \r\n\r\n within maxHeaderSize bytes — e.g. a part with thousands of header lines, extremely long single header values, or binary body data mistaken for headers after a missed boundary.
Common situations: Legitimate clients attaching very large custom headers or metadata per part; malicious header flooding; a wrong boundary causing the parser to interpret body bytes as header bytes.
Related errors
- Exceeded maximum number of parts
- Expected at most ${maxTransforms} request transforms
- Request is not a multipart request
- Request body is empty
- Invalid Content-Type header: missing boundary
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/a79460193348b4ff.
Report an issue: GitHub.