{"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/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/22_body.js#L437-L473","documentation":"In packageBytes (ext/fetch/22_body.js), when .formData() is called and the Content-Type essence is exactly multipart/form-data, the MIME parameter list must contain a boundary. If mimeType.parameters.get(\"boundary\") returns null (parameter absent - an empty value takes a different error path), this TypeError is thrown before any parsing starts.","triggerScenarios":"await res.formData() when the server replied Content-Type: multipart/form-data with no boundary parameter; test mocks with hand-written multipart Content-Types.","commonSituations":"Hand-rolled servers or mock fetch implementations that set multipart/form-data without generating a boundary; API gateways that rewrite or strip Content-Type parameters; bug reports that only reproduce behind certain proxies.","solutions":["Fix the sender: real multipart writers always emit boundary=... (browser FormData and fetch do it automatically)","Pre-check the header: if the content type is multipart, require /boundary=/i before calling formData()","If you control both ends and do not need multipart, switch to application/x-www-form-urlencoded"],"exampleFix":"// before\nconst form = await req.formData(); // boundary param missing -> TypeError\n\n// after\nconst ct = req.headers.get(\"content-type\") ?? \"\";\nif (/multipart\\/form-data/i.test(ct) && !/boundary=/i.test(ct)) {\n  return new Response(\"multipart content-type missing boundary\", { status: 400 });\n}\nconst form = await req.formData();","handlingStrategy":"validation","validationCode":"const ct = req.headers.get(\"content-type\") ?? \"\";\nif (/multipart\\/form-data/i.test(ct) && !/boundary=[^;]/i.test(ct)) {\n  return new Response(\"boundary parameter required\", { status: 400 });\n}\nconst form = await req.formData();","typeGuard":"function isParsableMultipart(contentType: string | null): boolean {\n  return contentType != null && /multipart\\/form-data;\\s*boundary=[^;]+/i.test(contentType);\n}","tryCatchPattern":"try { return await req.formData(); } catch (e) {\n  if (e instanceof TypeError && e.message.includes(\"missing boundary parameter\")) {\n    return new Response(\"multipart content-type missing boundary\", { status: 400 });\n  }\n  throw e;\n}","preventionTips":["Always emit boundary=... when you set a multipart content-type yourself","Validate untrusted Content-Type headers before calling formData()","Prefer letting the platform (FormData + fetch) generate boundaries"],"tags":["fetch","form-data","multipart","http"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}