denoland/deno · error · TypeError

Blob URL fetch only supports GET method

Error message

Blob URL fetch only supports GET method

What it means

A blob: URL references in-memory Blob data, not a network resource. Deno's fetch layer serves blob URLs only for GET requests; any other method (POST, PUT, HEAD, DELETE, ...) is rejected before the blob is even looked up, because a blob URL has no server that could accept a method other than retrieval.

Solutions

  1. Omit method (or use 'GET') when fetching a blob: URL
  2. Read the Blob directly with await blob.arrayBuffer() / blob.text() instead of fetching it
  3. For a real upload, send the blob bytes to the actual http(s): endpoint, not the blob URL

Example fix

// before
const url = URL.createObjectURL(new Blob([bytes]));
await fetch(url, { method: "POST" }); // TypeError

// after
const buf = await blob.arrayBuffer();
await fetch("https://api.example.com/upload", { method: "POST", body: buf });
Defensive patterns

Strategy: validation

Validate before calling

const isBlobUrl = (input) =>
  (typeof input === "string" ? input : input.url).startsWith("blob:");

const method = (init?.method ?? "GET").toUpperCase();
if (isBlobUrl(url) && method !== "GET") {
  const buf = await blob.arrayBuffer(); // read the Blob directly
  // send buf to the real http(s) endpoint instead
}

Try / catch

try {
  await fetch(url, init);
} catch (err) {
  if (err instanceof TypeError && err.message.includes("Blob URL")) {
    // programmer error: fix the method or bypass the blob URL
  } else throw err;
}

Prevention

When it happens

Trigger: fetch(blobUrl, { method: 'POST' }) or any non-GET method where blobUrl was produced by URL.createObjectURL(blob); passing a Request object whose method is not GET and whose URL is a blob: URL.

Common situations: Generic upload helpers that always set method: 'PUT'/'POST' and are later pointed at blob URLs; tests that fake endpoints with blob URLs but keep the real method; browser-ported code where the same restriction exists.

Related errors


AI-assisted analysis of denoland/deno@a961cdec3b (2026-08-20). Data as JSON: /api/errors/29509f21c2e735e3. Report an issue: GitHub.

Appendix: source

Thrown at ext/fetch/26_fetch.js:407

  // occurs. This applies to every hop, including those reached via redirects.
  //
  // Per https://fetch.spec.whatwg.org/#block-bad-port the check only applies
  // when the URL's scheme is an HTTP(S) scheme, so https bad ports (e.g.
  // https://example.com:22) are blocked too, while non-HTTP(S) schemes are
  // left alone. The spec's ALPN note covers *new* protocols negotiated over
  // TLS; it does not exempt https fetch from the list. This matches Node's
  // undici (`requestBadPort` gates on `urlIsHttpHttpsScheme`).
  const url = new URL(req.currentUrl());
  if (
    (url.protocol === "http:" || url.protocol === "https:") &&
    url.port !== "" && BAD_PORTS[url.port] === true
  ) {
    return networkError(`Requests to port ${url.port} are blocked`);
  }

  if (req.blobUrlEntry !== null) {
    if (req.method !== "GET") {
      throw new TypeError("Blob URL fetch only supports GET method");
    }

    const body = new InnerBody(req.blobUrlEntry.stream());
    terminator[abortSignal.add](() => body.error(terminator.reason));
    processUrlList(req.urlList, req.urlListProcessed);

    return {
      headerList: [
        ["content-length", String(req.blobUrlEntry.size)],
        ["content-type", req.blobUrlEntry.type],
      ],
      status: 200,
      statusMessage: "OK",
      body,
      type: "basic",
      url() {
        if (this.urlList.length == 0) return null;
        return this.urlList[this.urlList.length - 1];

View on GitHub (pinned to a961cdec3b)