{"record":{"id":"5dcdf9a9a5e6c7e0","repo":"denoland/deno","slug":"multipart-part-headers-are-too-large","errorCode":null,"errorMessage":"Multipart part headers are too large","messagePattern":"Multipart part headers are too large","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/21_formdata.js","lineNumber":554,"sourceCode":"    const formData = new FormData();\n    if (initialDelimiter.type === 2) {\n      return formData;\n    }\n\n    let headerText = \"\";\n    let headerStart = initialDelimiter.headerStart;\n    let state = 1;\n    let fileStart = 0;\n\n    for (let i = headerStart; i < this.body.length; i++) {\n      const byte = this.body[i];\n      const prevByte = this.body[i - 1];\n      const isNewLine = byte === LF && prevByte === CR;\n\n      if (state === 1) {\n        const headerByteLength = i - headerStart + 1;\n        if (headerByteLength > MAX_MULTIPART_PART_HEADER_SIZE) {\n          throw new TypeError(\"Multipart part headers are too large\");\n        }\n        if (\n          isNewLine && this.body[i + 1] === CR &&\n          this.body[i + 2] === LF\n        ) {\n          // end of the headers section\n          headerText = decodeLatin1Bytes(\n            TypedArrayPrototypeSubarray(this.body, headerStart, i + 1),\n          );\n          state = 2;\n          fileStart = i + 3; // After \\r\\n\n        }\n      } else if (state === 2) {\n        if (isNewLine) {\n          const delimiter = this.#matchDelimiter(i + 1);\n          if (delimiter === null) {\n            continue;\n          }","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/fetch/21_formdata.js#L536-L572","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Filenames or field names with megabyte-sized strings; hostile oversized-header uploads (resource-exhaustion hardening); truncated bodies that never contain the blank-line separator.","solutions":["Keep part headers small: short field names and filenames (URL-encode long metadata and pass it in a separate field).","Return 400 when formData() throws TypeError on untrusted input.","Enforce an overall request body size limit upstream so oversized parts never reach the multipart parser."],"exampleFix":"// server hardening\nlet form;\ntry {\n  form = await request.formData();\n} catch (e) {\n  if (e instanceof TypeError) return new Response(\"form data rejected\", { status: 400 });\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Keep part metadata (filenames, field names) well under 16 KiB per part.","Pass large metadata in body fields, not headers of a part.","Rate-limit and size-limit upload endpoints so limits are hit upstream of the parser."],"tags":["form-data","multipart","limits","dos-hardening"],"backgroundTag":"multipart-parse-limit-exceeded","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}