denoland/deno · error · TypeError

Request with GET/HEAD method cannot have body

Error message

Request with GET/HEAD method cannot have body

What it means

Request constructor step 35 enforces the fetch-spec rule that GET and HEAD requests have no body. The TypeError fires when init.body is non-null, or when the input is an existing Request that already carries a body and the effective method (from init.method or the input itself) is GET/HEAD.

Solutions

  1. Move the data into the URL query string for GET: url.searchParams.set(...)
  2. Or switch the method to POST/PUT/PATCH if a body is required
  3. When deriving from an input request, drop its body: pass init.body: null and don't reuse the input's body

Example fix

// before
new Request("https://example.com/search", { method: "GET", body: "q=deno" }); // throws

// after
const url = new URL("https://example.com/search");
url.searchParams.set("q", "deno");
new Request(url, { method: "GET" });
Defensive patterns

Strategy: validation

Validate before calling

function buildRequest(url, method, body) {
  const hasBody = body !== undefined && body !== null;
  if ((method === "GET" || method === "HEAD") && hasBody) {
    const u = new URL(url);
    for (const [k, v] of new URLSearchParams(body)) u.searchParams.append(k, v);
    return new Request(u, { method });
  }
  return new Request(url, { method, body });
}

Type guard

function bodyAllowedForMethod(method: string, body: unknown): boolean {
  const m = method.toUpperCase();
  return !(m === "GET" || m === "HEAD") || body === undefined || body === null;
}

Try / catch

try {
  new Request(url, { method, body });
} catch (err) {
  if (err instanceof TypeError && err.message.includes("GET/HEAD")) {
    // move body into query params, or switch to POST — do not silently drop it
    throw err;
  } else throw err;
}

Prevention

When it happens

Trigger: new Request(url, { method: "GET", body: "x=1" }); { method: "HEAD", body: formData }; new Request(existingPostRequest, { method: "GET" }) where the input request has a body.

Common situations: Toggling a POST helper to GET but keeping the body argument; generic request builders that always attach a body; wrapping an existing POST Request with a method override.

Related errors


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

Appendix: source

Thrown at ext/fetch/23_request.js:561

      if (headerList.length !== 0) {
        ArrayPrototypeSplice(headerList, 0, headerList.length);
      }
      fillHeaders(this[_headers], headers);
    }

    // 34.
    let inputBody = null;
    if (ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) {
      inputBody = input[_body];
    }

    // 35.
    if (
      (request.method === "GET" || request.method === "HEAD") &&
      ((init.body !== undefined && init.body !== null) ||
        inputBody !== null)
    ) {
      throw new TypeError("Request with GET/HEAD method cannot have body");
    }

    // 36.
    let initBody = null;

    // 37.
    if (init.body !== undefined && init.body !== null) {
      const res = extractBody(init.body);
      initBody = res.body;
      if (res.contentType !== null && !this[_headers].has("content-type")) {
        this[_headers].append("Content-Type", res.contentType);
      }
    }

    // 38.
    const inputOrInitBody = initBody ?? inputBody;

    // 40.

View on GitHub (pinned to 9ad36f7a2c)