denoland/deno · error · TypeError
Multipart part has too many headers
Error message
Multipart part has too many headers
What it means
A hardening limit inside MultipartParser.#parseHeaders (ext/fetch/21_formdata.js). Each header-looking line (one containing ':') increments a counter, and exceeding MAX_MULTIPART_PART_HEADER_COUNT = 128 (line 392) throws this TypeError. The limit exists so a hostile or runaway multipart body cannot make the parser build an unbounded Headers object.
Source
Thrown at ext/fetch/21_formdata.js:435
}
/**
* @param {string} headersText
* @returns {{ headers: Headers, disposition: Map<string, string> }}
*/
#parseHeaders(headersText) {
const headers = new Headers();
const rawHeaders = StringPrototypeSplit(headersText, "\r\n");
let headerCount = 0;
for (let i = 0; i < rawHeaders.length; ++i) {
const rawHeader = rawHeaders[i];
const sepIndex = StringPrototypeIndexOf(rawHeader, ":");
if (sepIndex < 0) {
continue; // Skip this header
}
headerCount++;
if (headerCount > MAX_MULTIPART_PART_HEADER_COUNT) {
throw new TypeError("Multipart part has too many headers");
}
const key = StringPrototypeSlice(rawHeader, 0, sepIndex);
const value = StringPrototypeSlice(rawHeader, sepIndex + 1);
headers.set(key, value);
}
const disposition = parseContentDisposition(
headers.get("Content-Disposition") ?? "",
);
return { headers, disposition };
}
/**
* @param {number} index
* @returns {0 | 1 | 2}
*/
#delimiterType(index) {View on GitHub (pinned to 89f33cbef2)
Solutions
- Fix the producer: cap and de-duplicate part headers well below 128 (well-behaved parts need ~5)
- Move per-part metadata into form fields rather than custom headers
- Treat the throw as a 400 when parsing untrusted requests: wrap formData() in try/catch and reject
Example fix
// before (sender)
for (const [k, v] of Object.entries(meta)) partHeaders.set(k, v)); // can exceed 128
// after (sender)
for (const [k, v] of Object.entries(meta)) form.set(`meta_${k}`, String(v))); // fields, not headers Defensive patterns
Strategy: try-catch
Validate before calling
// sender side: keep part headers far below the 128 limit
const MAX_PART_HEADERS = 100;
if (Object.keys(partHeaders).length > MAX_PART_HEADERS) {
throw new Error("too many part headers; move metadata into form fields");
} Try / catch
try { return await req.formData(); } catch (e) {
if (e instanceof TypeError && e.message.includes("too many headers")) {
return new Response("malformed multipart part", { status: 400 });
}
throw e;
} Prevention
- Cap and de-duplicate part headers at the producer
- Put per-part metadata in form fields, not custom headers
- Treat multipart parser TypeErrors from untrusted bodies as 400s, not 500s
When it happens
Trigger: A single multipart part whose header block contains more than 128 lines with ':' characters; a generator loop that appends the same header repeatedly; malformed bodies where a missing \r\n\r\n terminator causes data lines to be counted as headers.
Common situations: Custom multipart writers that duplicate headers per part; security/fuzz testing corpora; feeds that stuff metadata into part headers instead of the body.
Related errors
- Multipart part headers are too large
- 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/070a6b88b76386be.
Report an issue: GitHub.