remix-run/remix · error · MultipartParseError
Multipart boundary exceeds maximum length of ${maxBoundaryLe
Error message
Multipart boundary exceeds maximum length of ${maxBoundaryLength} characters What it means
The MultipartParser constructor rejects boundaries longer than the RFC 2046 limit (maxBoundaryLength, 70 characters). Oversized boundaries are almost always a symptom of malformed input or a corrupted header, so construction fails fast instead of mis-parsing.
Source
Thrown at packages/multipart-parser/src/lib/multipart.ts:262
#findPartialTailBoundary: PartialTailSearchFunction
#boundaryLength: number
#boundaryBytes: Uint8Array
#state = MultipartParserStateStart
#buffer: Uint8Array | null = null
#currentHeader: Uint8Array | null = null
#currentContent: Uint8Array[] | null = null
#contentLength = 0
#partCount = 0
#totalContentLength = 0
/**
* @param boundary The boundary string used to separate parts
* @param options Options for the parser
*/
constructor(boundary: string, options?: MultipartParserOptions) {
if (boundary.length > maxBoundaryLength) {
throw new MultipartParseError(
`Multipart boundary exceeds maximum length of ${maxBoundaryLength} characters`,
)
}
this.boundary = boundary
this.maxHeaderSize = options?.maxHeaderSize ?? 8 * oneKb
this.maxFileSize = options?.maxFileSize ?? 2 * oneMb
this.maxParts = options?.maxParts ?? defaultMaxParts
this.maxTotalSize =
options?.maxTotalSize ?? this.maxFileSize * defaultMaxTotalSizePartAllowance + oneMb
this.#findOpeningBoundary = createSearch(`--${boundary}`)
this.#openingBoundaryLength = 2 + boundary.length // length of '--' + boundary
let boundaryPattern = `\r\n--${boundary}`
this.#findBoundary = createSearch(boundaryPattern)
this.#findPartialTailBoundary = createPartialTailSearch(boundaryPattern)
this.#boundaryLength = 4 + boundary.length // length of '\r\n--' + boundary
this.#boundaryBytes = encodeAsciiPattern(boundaryPattern)View on GitHub (pinned to 9696913134)
Solutions
- Reject or truncate requests whose boundary parameter exceeds 70 characters before parsing (a 4xx response is appropriate)
- Regenerate the boundary with a standard short random value (e.g. crypto.randomUUID() based)
- Fix test fixtures to use realistic boundaries
Example fix
// before
new MultipartParser('x'.repeat(200))
// after
let boundary = `----node${crypto.randomUUID()}`
new MultipartParser(boundary) Defensive patterns
Strategy: validation
Validate before calling
const MAX_BOUNDARY = 70
if (boundary.length > MAX_BOUNDARY) {
throw new Response(`Boundary too long (max ${MAX_BOUNDARY})`, { status: 400 })
} Try / catch
try {
new MultipartParser(boundary)
} catch (error) {
if (error instanceof MultipartParseError && error.message.includes('maximum length')) {
return new Response('Invalid multipart boundary', { status: 400 })
}
throw error
} Prevention
- Generate boundaries from short random values (UUID-based), never user input
- Validate boundary length before constructing the parser
When it happens
Trigger: new MultipartParser(boundary) where boundary.length exceeds 70 characters; or parseMultipartRequest/parseMultipartStream deriving such a boundary from a Content-Type header with a huge boundary value.
Common situations: Malicious or fuzzed requests with inflated boundary parameters; copy-paste errors embedding whitespace/base64 blobs into the boundary; hand-written test fixtures with arbitrary long delimiters.
Related errors
- Invalid Content-Type header: missing boundary
- Invalid Content-Type header: missing boundary
- Invalid multipart stream: missing initial boundary
- hmr must create a channel with a close function
- hmr must create a channel with an onFileEvents function
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/aee05f8410a36457.
Report an issue: GitHub.