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

  1. Ensure the body literally starts with (or contains) `--` + the exact boundary from the content type, and parts end with `--boundary--`.
  2. Prefer `new FormData()` + fetch so boundary and body always match.
  3. 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

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

Related errors


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)