denoland/deno · error · TypeError
Multipart part headers are too large
Error message
Multipart part headers are too large
What it means
A size hardening limit in MultipartParser.parseBody(): while scanning state 1 (the header section of a part), the byte span from headerStart to the current position must stay <= MAX_MULTIPART_PART_HEADER_SIZE = 16 * 1024 (line 391). A part whose headers (including a giant Content-Disposition) exceed 16 KiB throws this TypeError; so does a malformed body whose \r\n\r\n header terminator never arrives, letting body bytes be miscounted as headers until the cap hits.
Source
Thrown at ext/fetch/21_formdata.js:512
let headerText = "";
let headerStart = 0;
let state = 0;
let fileStart = 0;
for (let i = 0; i < this.body.length; i++) {
const byte = this.body[i];
const prevByte = this.body[i - 1];
const isNewLine = byte === LF && prevByte === CR;
if (state === 0 && isNewLine) {
state = 1;
headerStart = i + 1;
} else if (
state === 1
) {
const headerByteLength = i - headerStart + 1;
if (headerByteLength > MAX_MULTIPART_PART_HEADER_SIZE) {
throw new TypeError("Multipart part headers are too large");
}
if (
isNewLine && this.body[i + 1] === CR &&
this.body[i + 2] === LF
) {
// end of the headers section
headerText = decodeLatin1Bytes(
TypedArrayPrototypeSubarray(this.body, headerStart, i + 1),
);
state = 2;
fileStart = i + 3; // After \r\n
}
} else if (state === 2) {
if (isNewLine) {
const delimiterType = this.#delimiterType(i + 1);
if (delimiterType === 0) {
continue;
}View on GitHub (pinned to 89f33cbef2)
Solutions
- Keep part headers small - filenames shorter, metadata in form fields, not headers
- On the receive side, wrap formData() in try/catch and translate this TypeError into a 413/400 response
- If generating multipart manually, verify each part emits a proper \r\n\r\n after its header block
Example fix
// before (sender)
partHeaders.set("content-disposition", `form-data; name="f"; filename="${rawName}"`);
// after (sender)
const safeName = rawName.replaceAll(/["\r\n]/g, "_").slice(0, 255);
partHeaders.set("content-disposition", `form-data; name="f"; filename="${safeName}"`); Defensive patterns
Strategy: try-catch
Validate before calling
// sender side: bound header-block size before emitting a part
const headerBlock = partHeaderLines.join("\r\n");
if (headerBlock.length > 16 * 1024) {
throw new Error("part headers exceed 16 KiB; shorten filenames / drop metadata");
} Try / catch
try { return await req.formData(); } catch (e) {
if (e instanceof TypeError && e.message.includes("headers are too large")) {
return new Response("part headers too large", { status: 413 });
}
throw e;
} Prevention
- Sanitize uploaded filenames (strip quotes/CRLF, cap length ~255)
- Keep part metadata out of headers; 16 KiB per part is the hard ceiling
- Ensure every generated part ends its header block with \r\n\r\n
When it happens
Trigger: A part with an extremely long Content-Disposition filename; many headers totalling >16 KiB; a body missing the CRLFCRLF separator so headers never terminate.
Common situations: Uploads of files with very long names packed into Content-Disposition; clients that stuff JSON metadata into custom part headers; hostile payloads in security tests probing parser limits.
Related errors
- Multipart part has too many headers
- Cannot construct MultipartParser: multipart/form-data must p
- Unable to parse body as form data
- Cannot turn into form data: missing boundary parameter in mi
- Body can not be decoded as form data
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/5dcdf9a9a5e6c7e0.
Report an issue: GitHub.