denoland/deno · error · TypeError
Body can not be decoded as form data
Error message
Body can not be decoded as form data
What it means
In packageBytes, .formData() only decodes two content types: multipart/form-data and application/x-www-form-urlencoded. If a Content-Type is present but its essence is anything else (text/plain, application/json, ...), parsing stops with this TypeError - the body will not be reinterpreted as form data.
Source
Thrown at ext/fetch/22_body.js:470
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");
}
case "JSON":
return JSONParse(chunkToString(bytes));
case "text":
return chunkToString(bytes);
}
}
/**
* @param {BodyInit} object
* @returns {{body: InnerBody, contentType: string | null}}
*/
function extractBody(object) {
/** @type {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} */
let stream;
let source = null;View on GitHub (pinned to 89f33cbef2)
Solutions
- Branch on the Content-Type: JSON.parse(await req.text()) for application/json, formData() only for the two form types
- Fix the client to send application/x-www-form-urlencoded or multipart/form-data
- Return 415 Unsupported Media Type when the type is not one your handler supports
Example fix
// before
const form = await req.formData(); // client sent application/json -> throws
// after
const ct = req.headers.get("content-type") ?? "";
if (ct.includes("application/json")) {
const data = await req.json(); /* ... */
} else if (ct.includes("form-data") || ct.includes("urlencoded")) {
const form = await req.formData(); /* ... */
} else {
return new Response("unsupported media type", { status: 415 });
} Defensive patterns
Strategy: validation
Validate before calling
const ct = req.headers.get("content-type") ?? "";
if (!/multipart\/form-data|application\/x-www-form-urlencoded/i.test(ct)) {
return new Response("expected form data", { status: 415 });
}
const form = await req.formData(); Type guard
function isFormDataContentType(ct: string | null): boolean {
if (ct == null) return false;
const essence = ct.split(";")[0].trim().toLowerCase();
return essence === "multipart/form-data" || essence === "application/x-www-form-urlencoded";
} Try / catch
try { return await req.formData(); } catch (e) {
if (e instanceof TypeError && e.message.includes("can not be decoded as form data")) {
return new Response("send multipart/form-data or x-www-form-urlencoded", { status: 415 });
}
throw e;
} Prevention
- Dispatch parsers by Content-Type essence, not by endpoint convention
- Set the content-type explicitly on every form-posting client
- Reject unsupported media types with 415 before attempting to parse
When it happens
Trigger: await req.formData() on a request posted with Content-Type: text/plain or application/json; senders that default to text/plain when no explicit type is set (older fetch or curl -d without --data-urlencode).
Common situations: Accepting form posts while the client library actually sends JSON; curl-based integrations that forget the content-type flag; endpoints that multiplex JSON and form data but always call formData().
Related errors
- Missing content type
- Cannot construct MultipartParser: multipart/form-data must p
- Cannot turn into form data: missing boundary parameter in mi
- Invalid header name: "${name}"
- Invalid header value: "${value}"
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/b60a7e46229c113d.
Report an issue: GitHub.