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
- Omit method (or use 'GET') when fetching a blob: URL
- Read the Blob directly with await blob.arrayBuffer() / blob.text() instead of fetching it
- 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
- Treat blob: URLs as read-only GET resources
- Route uploads through the real HTTP endpoint, never a blob URL
- In generic fetch wrappers, special-case blob/data URLs before applying method overrides
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
- Method is forbidden
- Method is not valid
- Request with GET/HEAD method cannot have body
- Body already consumed
- Body already consumed.
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)