denoland/deno · error · TypeError

Multipart part headers are too large

Error message

Multipart part headers are too large

What it means

Thrown by MultipartParser.parse() when the header section of a part exceeds MAX_MULTIPART_PART_HEADER_SIZE (16 KiB, ext/fetch/21_formdata.js:393). The state machine counts bytes from headerStart until the \r\n\r\n terminator; if the blank line never arrives within 16384 bytes, parsing aborts.

Solutions

  1. Keep part headers small: short field names and filenames (URL-encode long metadata and pass it in a separate field).
  2. Return 400 when formData() throws TypeError on untrusted input.
  3. Enforce an overall request body size limit upstream so oversized parts never reach the multipart parser.

Example fix

// server hardening
let form;
try {
  form = await request.formData();
} catch (e) {
  if (e instanceof TypeError) return new Response("form data rejected", { status: 400 });
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try { await request.formData(); } catch (e) { if (e instanceof TypeError && /headers are too large|form data/i.test(e.message)) return new Response("multipart headers too large", { status: 400 }); throw e; }

Prevention

When it happens

Trigger: `await request.formData()` where a part's header block (before the first \r\n\r\n) is larger than 16 KiB — e.g. a huge Content-Disposition with a long filename, a header line missing its colon so the block never terminates at the right place, or garbage bytes labeled as multipart.

Common situations: Filenames or field names with megabyte-sized strings; hostile oversized-header uploads (resource-exhaustion hardening); truncated bodies that never contain the blank-line separator.

Related errors


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

Appendix: source

Thrown at ext/fetch/21_formdata.js:554

    const formData = new FormData();
    if (initialDelimiter.type === 2) {
      return formData;
    }

    let headerText = "";
    let headerStart = initialDelimiter.headerStart;
    let state = 1;
    let fileStart = 0;

    for (let i = headerStart; i < this.body.length; i++) {
      const byte = this.body[i];
      const prevByte = this.body[i - 1];
      const isNewLine = byte === LF && prevByte === CR;

      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 delimiter = this.#matchDelimiter(i + 1);
          if (delimiter === null) {
            continue;
          }

View on GitHub (pinned to 9ad36f7a2c)