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

  1. Keep part headers small - filenames shorter, metadata in form fields, not headers
  2. On the receive side, wrap formData() in try/catch and translate this TypeError into a 413/400 response
  3. 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

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


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/5dcdf9a9a5e6c7e0. Report an issue: GitHub.