{"record":{"id":"b6272e4358be0403","repo":"denoland/deno","slug":"cannot-turn-into-form-data-missing-boundary-param","errorCode":null,"errorMessage":"Cannot turn into form data: missing boundary parameter in mime type of multipart form data","messagePattern":"Cannot turn into form data: missing boundary parameter in mime type of multipart form data","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/22_body.js","lineNumber":455,"sourceCode":" * @param {MimeType | null} [mimeType]\n */\nfunction packageData(bytes, type, mimeType) {\n  switch (type) {\n    case \"ArrayBuffer\":\n      return TypedArrayPrototypeGetBuffer(chunkToU8(bytes));\n    case \"Blob\":\n      return new Blob([bytes], {\n        type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : \"\",\n      });\n    case \"bytes\":\n      return chunkToU8(bytes);\n    case \"FormData\": {\n      if (mimeType !== null) {\n        const essence = mimesniff.essence(mimeType);\n        if (essence === \"multipart/form-data\") {\n          const boundary = mimeType.parameters.get(\"boundary\");\n          if (boundary === null) {\n            throw new TypeError(\n              \"Cannot turn into form data: missing boundary parameter in mime type of multipart form data\",\n            );\n          }\n          return parseFormData(chunkToU8(bytes), boundary);\n        } else if (essence === \"application/x-www-form-urlencoded\") {\n          // TODO(@AaronO): pass as-is with StringOrBuffer in op-layer\n          const entries = parseUrlEncoded(chunkToU8(bytes));\n          return formDataFromEntries(\n            ArrayPrototypeMap(\n              entries,\n              (x) => ({ name: x[0], value: x[1] }),\n            ),\n          );\n        }\n        throw new TypeError(\"Body can not be decoded as form data\");\n      }\n      throw new TypeError(\"Missing content type\");\n    }","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/fetch/22_body.js#L437-L473","documentation":"Thrown in packageBytes() (ext/fetch/22_body.js) when decoding bytes to FormData: the MIME type's essence is exactly multipart/form-data, but the parameters contain no `boundary` entry. This parallels the MultipartParser constructor check and fires during response.formData() / request.formData() decoding.","triggerScenarios":"`await response.formData()` with `Content-Type: multipart/form-data` lacking `; boundary=...`. Note the nuance: mimeType.parameters.get(\"boundary\") must exist — an empty boundary value (`boundary=`) parses as an empty-string parameter and passes here, failing later in the parser.","commonSituations":"Upstream servers or proxies that strip the boundary when forwarding; hardcoded content types in mocks/tests; responses from services that assume urlencoded but are labeled multipart.","solutions":["Make the sender include the boundary: `Content-Type: multipart/form-data; boundary=X`.","On the client, extract and check the boundary yourself before calling formData(): parse content-type and bail with a clear error if missing.","If the body is actually urlencoded, fix the content type to application/x-www-form-urlencoded so it parses via that path."],"exampleFix":"// before\nconst ct = \"multipart/form-data\"; // boundary lost\nconst res = new Response(bodyBytes, { headers: { \"content-type\": ct } });\nawait res.formData(); // throws\n\n// after\nconst res = new Response(bodyBytes, {\n  headers: { \"content-type\": \"multipart/form-data; boundary=BDY\" },\n});\nawait res.formData();","handlingStrategy":"validation","validationCode":"const ct = res.headers.get(\"content-type\") ?? \"\";\nconst essence = ct.split(\";\")[0].trim().toLowerCase();\nif (essence === \"multipart/form-data\" && !/boundary=[^;\\s]+/i.test(ct)) {\n  throw new Error(\"upstream dropped the multipart boundary\");\n}","typeGuard":null,"tryCatchPattern":"try { await res.formData(); } catch (e) { if (e instanceof TypeError && e.message.includes(\"missing boundary\")) { /* fix upstream content-type or reject */ } else throw e; }","preventionTips":["Preserve full Content-Type including parameters when forwarding responses.","Assert boundary presence in integration tests for multipart endpoints.","Prefer urlencoded for simple form posts where boundary bookkeeping is impossible."],"tags":["form-data","multipart","content-type","fetch"],"backgroundTag":"missing-multipart-boundary","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"}