denoland/deno · error · TypeError
Cannot turn into form data: missing boundary parameter in…
Error message
Cannot turn into form data: missing boundary parameter in mime type of multipart form data
What it means
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.
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.
Example fix
// before
const ct = "multipart/form-data"; // boundary lost
const res = new Response(bodyBytes, { headers: { "content-type": ct } });
await res.formData(); // throws
// after
const res = new Response(bodyBytes, {
headers: { "content-type": "multipart/form-data; boundary=BDY" },
});
await res.formData(); Defensive patterns
Strategy: validation
Validate before calling
const ct = res.headers.get("content-type") ?? "";
const essence = ct.split(";")[0].trim().toLowerCase();
if (essence === "multipart/form-data" && !/boundary=[^;\s]+/i.test(ct)) {
throw new Error("upstream dropped the multipart boundary");
} Try / catch
try { await res.formData(); } catch (e) { if (e instanceof TypeError && e.message.includes("missing boundary")) { /* fix upstream content-type or reject */ } else throw e; } Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- Cannot construct MultipartParser: multipart/form-data must…
- Body can not be decoded as form data
- Missing content type
- Unable to parse body as form data
- Invalid WebAssembly content type
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/b6272e4358be0403.
Report an issue: GitHub.
Appendix: source
Thrown at ext/fetch/22_body.js:455
* @param {MimeType | null} [mimeType]
*/
function packageData(bytes, type, mimeType) {
switch (type) {
case "ArrayBuffer":
return TypedArrayPrototypeGetBuffer(chunkToU8(bytes));
case "Blob":
return new Blob([bytes], {
type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : "",
});
case "bytes":
return chunkToU8(bytes);
case "FormData": {
if (mimeType !== null) {
const essence = mimesniff.essence(mimeType);
if (essence === "multipart/form-data") {
const boundary = mimeType.parameters.get("boundary");
if (boundary === null) {
throw new TypeError(
"Cannot turn into form data: missing boundary parameter in mime type of multipart form data",
);
}
return parseFormData(chunkToU8(bytes), boundary);
} else if (essence === "application/x-www-form-urlencoded") {
// TODO(@AaronO): pass as-is with StringOrBuffer in op-layer
const entries = parseUrlEncoded(chunkToU8(bytes));
return formDataFromEntries(
ArrayPrototypeMap(
entries,
(x) => ({ name: x[0], value: x[1] }),
),
);
}
throw new TypeError("Body can not be decoded as form data");
}
throw new TypeError("Missing content type");
}View on GitHub (pinned to 9ad36f7a2c)