denoland/deno · error · TypeError

Request url protocol must be 'http:' or 'https:': received '

Error message

Request url protocol must be 'http:' or 'https:': received '${reqUrl.protocol}'

What it means

Cache.put() implements the ServiceWorker Cache API algorithm; step 4 requires the request URL scheme to be http: or https:. The Cache API stores only network resources, so data:, blob:, file: and other schemes are rejected.

Source

Thrown at ext/cache/01_cache.js:149

    request = webidl.converters["RequestInfo_DOMString"](
      request,
      prefix,
      "Argument 1",
    );
    response = webidl.converters["Response"](response, prefix, "Argument 2");
    // Step 1.
    let innerRequest = null;
    // Step 2.
    if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
      innerRequest = toInnerRequest(request);
    } else {
      // Step 3.
      innerRequest = toInnerRequest(new Request(request));
    }
    // Step 4.
    const reqUrl = new URL(innerRequest.url());
    if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") {
      throw new TypeError(
        `Request url protocol must be 'http:' or 'https:': received '${reqUrl.protocol}'`,
      );
    }
    if (innerRequest.method !== "GET") {
      throw new TypeError("Request method must be GET");
    }
    // Step 5.
    const innerResponse = toInnerResponse(response);
    // Step 6.
    if (innerResponse.status === 206) {
      throw new TypeError("Response status must not be 206");
    }
    // Step 7.
    const varyHeader = getHeader(innerResponse.headerList, "vary");
    if (varyHeader) {
      const fieldValues = StringPrototypeSplit(varyHeader, ",");
      for (let i = 0; i < fieldValues.length; ++i) {
        const field = fieldValues[i];

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Cache only http(s) URLs.
  2. Store non-HTTP content in Deno KV, SQLite, or the filesystem instead of the Cache API.
  3. Rebuild the Request from an http(s) URL before put() when a non-network Request object was constructed.

Example fix

// before
await cache.put(new Request(`data:${mime},${text}`), res);
// after (non-HTTP content belongs in storage, not Cache)
await kv.set(['assets', key], text);
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(typeof request === 'string' ? request : request.url);
if (u.protocol === 'http:' || u.protocol === 'https:') {
  await cache.put(request, response);
} else {
  await kv.set(['assets', u.href], response); // non-HTTP content: other storage
}

Try / catch

try { await cache.put(req, res); } catch (e) { if (e instanceof TypeError) { /* skip caching, app continues */ } else throw e; }

Prevention

When it happens

Trigger: cache.put(new Request('data:text/plain,hi'), response); cache.put('blob:...', response) or cache.put('file:///...', response) — any scheme other than http:/https:.

Common situations: Caching responses built from data: URLs or URL.createObjectURL blobs; reusing service-worker-style cache code against synthesized or local resources.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/a80e4e2699205e9b. Report an issue: GitHub.