denoland/deno · error · TypeError

Failed to receive WebAssembly content: HTTP status code

Error message

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

What it means

After the Content-Type check, Deno's streaming WebAssembly compile verifies res.ok (status 200-299). A non-2xx reply (404, 401, 403, 500, an HTML error page) is not valid WebAssembly, so instantiateStreaming/compileStreaming throws a TypeError that includes the exact HTTP status received.

Solutions

  1. Check res.ok (or res.status) before passing the response to the streaming API
  2. Fix the URL / asset manifest to point at the real .wasm file
  3. Send the credentials or headers the endpoint requires (fetch(url, { credentials: 'include' }))
  4. Debug once by reading await res.text() of the failing response to see the error page

Example fix

// before
const { instance } = await WebAssembly.instantiateStreaming(fetch(url));

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

Strategy: validation

Validate before calling

const res = await fetch(url);
if (!res.ok) {
  throw new Error(`wasm asset fetch failed: ${res.status} ${url}`);
}
const mod = await WebAssembly.instantiateStreaming(res);

Try / catch

try {
  mod = await WebAssembly.instantiateStreaming(res);
} catch (err) {
  if (err instanceof TypeError && /HTTP status code/.test(err.message)) {
    // wrong URL or auth: surface a clear deployment error
  } else throw err;
}

Prevention

When it happens

Trigger: WebAssembly.instantiateStreaming(fetch(url)) where the server returns 404 (wrong path), 401/403 (authentication required by a gateway), 500, or a redirect chain ending in an error page.

Common situations: Deployed asset paths wrong after hashed filenames changed between releases; CDN access tokens expired; missing credentials: 'include' so the gateway returns 401; reverse proxy serving a maintenance page.

Related errors


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

Appendix: source

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

    // 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 a961cdec3b)