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

  1. Make the sender include the boundary: `Content-Type: multipart/form-data; boundary=X`.
  2. On the client, extract and check the boundary yourself before calling formData(): parse content-type and bail with a clear error if missing.
  3. 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

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


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)