denoland/deno · error · TypeError
Unable to parse body as form data
Error message
Unable to parse body as form data
What it means
Thrown by MultipartParser.parse() when #findInitialDelimiter() returns null — the parser scanned the body for the first occurrence of `--boundary` (or preamble-terminated delimiter) and found none, so there is no multipart structure to parse at all.
Solutions
- Ensure the body literally starts with (or contains) `--` + the exact boundary from the content type, and parts end with `--boundary--`.
- Prefer `new FormData()` + fetch so boundary and body always match.
- On servers, catch TypeError from formData() and return 400 instead of crashing the handler.
Example fix
// before
const form = await request.formData(); // throws if body lacks --boundary
// after
let form;
try {
form = await request.formData();
} catch {
return new Response("invalid multipart body", { status: 400 });
} Defensive patterns
Strategy: try-catch
Validate before calling
const ct = req.headers.get("content-type") ?? "";
const m = ct.match(/boundary=(?:"([^"]+)"|([^;\s]+))/i);
if (!m) return new Response("boundary missing", { status: 400 });
// optionally verify body actually contains `--${m[1] ?? m[2]}` before parsing Try / catch
try { const form = await req.formData(); } catch (e) { if (e instanceof TypeError && e.message === "Unable to parse body as form data") return new Response("invalid multipart body", { status: 400 }); throw e; } Prevention
- Generate multipart bodies with a library or FormData, never by string concatenation.
- Verify the boundary in content-type matches the delimiters in the body in test fixtures.
- Return 400, not 500, for unparseable form bodies on public endpoints.
When it happens
Trigger: `await request.formData()` where the body does not contain the `--<boundary>` delimiter: empty body, wrong boundary in body vs content-type, body sent as application/x-www-form-urlencoded but labeled multipart, or a truncated upload.
Common situations: Boundary mismatch after a proxy rewrites content-type; client and server disagree on the boundary constant; body read as empty because it was already consumed or the request had no body; upstream tests posting raw bytes with a multipart content type.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Body can not be decoded as form data
- Cannot construct MultipartParser: multipart/form-data must…
- Cannot turn into form data: missing boundary parameter in…
- Missing content type
- Multipart part has too many headers
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/5daca81ee5011956.
Report an issue: GitHub.
Appendix: source
Thrown at ext/fetch/21_formdata.js:533
continue;
}
const delimiter = this.#matchDelimiter(index);
if (delimiter !== null) {
return { type: delimiter.type, headerStart: delimiter.nextIndex };
}
}
return null;
}
/**
* @returns {FormData}
*/
parse() {
const initialDelimiter = this.#findInitialDelimiter();
if (initialDelimiter === null) {
throw new TypeError("Unable to parse body as form data");
}
const formData = new FormData();
if (initialDelimiter.type === 2) {
return formData;
}
let headerText = "";
let headerStart = initialDelimiter.headerStart;
let state = 1;
let fileStart = 0;
for (let i = headerStart; i < this.body.length; i++) {
const byte = this.body[i];
const prevByte = this.body[i - 1];
const isNewLine = byte === LF && prevByte === CR;
if (state === 1) {View on GitHub (pinned to 9ad36f7a2c)