denoland/deno · error · TypeError

Missing content type

Error message

Missing content type

What it means

Thrown in packageBytes() when decoding bytes as FormData and the body has no Content-Type at all (mimeType === null). Without a type, the runtime cannot decide between multipart and urlencoded decoding, so it refuses rather than guessing.

Solutions

  1. Set the content type when constructing: `new Response(bytes, { headers: { "content-type": "application/x-www-form-urlencoded" } })`.
  2. Check `res.headers.get("content-type")` first and only call formData() when it is one of the two supported types.
  3. If you know the encoding, decode manually: new URLSearchParams(new TextDecoder().decode(bytes)).

Example fix

// before
const res = new Response("a=1&b=2");
await res.formData(); // Missing content type

// after
const res = new Response("a=1&b=2", {
  headers: { "content-type": "application/x-www-form-urlencoded" },
});
await res.formData();
Defensive patterns

Strategy: validation

Validate before calling

const ct = res.headers.get("content-type");
if (!ct) throw new Error("response has no content-type; cannot parse as form data");
const form = await res.formData();

Try / catch

try { await res.formData(); } catch (e) { if (e instanceof TypeError && e.message === "Missing content type") { /* supply known type and decode manually */ } else throw e; }

Prevention

When it happens

Trigger: `await res.formData()` on a Response constructed without headers: `new Response(bytes).formData()`; responses from fetch where the server sent no Content-Type header.

Common situations: Mock/stub responses built in tests without content-type; minimal Response construction in examples; servers omitting the header for HEAD or 204-adjacent payloads reused with formData().

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/2464e1a827c3fae3. Report an issue: GitHub.

Appendix: source

Thrown at ext/fetch/22_body.js:472

          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;
  let length = null;
  let contentType = null;

View on GitHub (pinned to 9ad36f7a2c)