denoland/deno · error · TypeError

Cannot turn into form data: missing boundary parameter in mi

Error message

Cannot turn into form data: missing boundary parameter in mime type of multipart form data

What it means

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.

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 89f33cbef2)

Solutions

  1. Fix the sender: real multipart writers always emit boundary=... (browser FormData and fetch do it automatically)
  2. Pre-check the header: if the content type is multipart, require /boundary=/i before calling formData()
  3. If you control both ends and do not need multipart, switch to application/x-www-form-urlencoded

Example fix

// before
const form = await req.formData(); // boundary param missing -> TypeError

// after
const ct = req.headers.get("content-type") ?? "";
if (/multipart\/form-data/i.test(ct) && !/boundary=/i.test(ct)) {
  return new Response("multipart content-type missing boundary", { status: 400 });
}
const form = await req.formData();
Defensive patterns

Strategy: validation

Validate before calling

const ct = req.headers.get("content-type") ?? "";
if (/multipart\/form-data/i.test(ct) && !/boundary=[^;]/i.test(ct)) {
  return new Response("boundary parameter required", { status: 400 });
}
const form = await req.formData();

Type guard

function isParsableMultipart(contentType: string | null): boolean {
  return contentType != null && /multipart\/form-data;\s*boundary=[^;]+/i.test(contentType);
}

Try / catch

try { return await req.formData(); } catch (e) {
  if (e instanceof TypeError && e.message.includes("missing boundary parameter")) {
    return new Response("multipart content-type missing boundary", { status: 400 });
  }
  throw e;
}

Prevention

When it happens

Trigger: await res.formData() when the server replied Content-Type: multipart/form-data with no boundary parameter; test mocks with hand-written multipart Content-Types.

Common situations: 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.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/b6272e4358be0403. Report an issue: GitHub.