denoland/deno · error · TypeError

Failed to receive WebAssembly content: HTTP status code ${re

Error message

Failed to receive WebAssembly content: HTTP status code ${res.status}

What it means

After the Content-Type check, streaming WebAssembly compilation requires the fetch result to be a successful response. A non-ok status (4xx/5xx) means the body is likely an error page rather than a module, so a TypeError carrying the received status is thrown before feeding the streaming compiler.

Source

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

    // 2.3.
    // The spec is ambiguous here, see
    // https://github.com/WebAssembly/spec/issues/1138. The WPT tests expect
    // the raw value of the Content-Type attribute lowercased. We ignore this
    // for file:// because file fetches don't have a Content-Type.
    if (!StringPrototypeStartsWith(res.url, "file://")) {
      const contentType = res.headers.get("Content-Type");
      if (
        typeof contentType !== "string" ||
        StringPrototypeToLowerCase(contentType) !== "application/wasm"
      ) {
        throw new TypeError("Invalid WebAssembly content type");
      }
    }

    // 2.5.
    if (!res.ok) {
      throw new TypeError(
        `Failed to receive WebAssembly content: HTTP status code ${res.status}`,
      );
    }

    // Pass the resolved URL to v8.
    op_wasm_streaming_set_url(rid, res.url);

    if (res.body !== null) {
      // 2.6.
      // Rather than consuming the body as an ArrayBuffer, this feeds each chunk
      // to the streaming compiler as soon as it's available. Instead of reading
      // the body chunk-by-chunk in JS and calling `op_wasm_streaming_feed` once
      // per chunk, hand the underlying stream resource to `op_pipe` with the
      // wasm streaming resource as the sink (`WasmStreamingResource` implements
      // `Resource::write`), so a single async op pumps the bytes straight into
      // V8's streaming compiler.
      const stream = res.body;
      const resourceBacking = getReadableStreamResourceBacking(stream);

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Check res.ok and log res.status before compiling when you control the fetch
  2. Fix the module URL (verify it with curl -I)
  3. Resolve the server-side error or authentication so the asset returns 200
  4. Handle non-ok statuses explicitly and only feed ok responses to the streaming compiler

Example fix

// before
const mod = await WebAssembly.compileStreaming(fetch(url)); // HTTP status code 404

// after
const res = await fetch(url);
if (!res.ok) throw new Error(`wasm fetch failed: ${res.status} ${res.url}`);
const mod = await WebAssembly.compileStreaming(Promise.resolve(res));
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(wasmUrl);
if (!res.ok) {
  throw new Error(`wasm module unavailable: ${res.status} ${res.statusText} for ${res.url}`);
}
const mod = await WebAssembly.compileStreaming(Promise.resolve(res));

Type guard

function isOkWasmResponse(res: Response): boolean {
  return res.ok && (res.headers.get("content-type") ?? "").toLowerCase().startsWith("application/wasm");
}

Try / catch

try {
  const mod = await WebAssembly.compileStreaming(fetch(url));
} catch (err) {
  if (err instanceof TypeError && /HTTP status code/.test(err.message)) {
    // bad URL or server error: verify the URL, re-check auth/CDN, do not retry blindly
  } else throw err;
}

Prevention

When it happens

Trigger: Module URL returns 404 (wrong path), 401/403 (auth-protected asset), or 500/502/503 (server or gateway failure) when passed to WebAssembly.instantiateStreaming/compileStreaming.

Common situations: Case-sensitive path mismatch on Linux servers; deployed assets missing after a partial release; reverse proxy serving HTML error pages for backend failures; expired auth tokens guarding static assets.

Related errors


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