evanw/esbuild · error · Error

Failed to download

Error message

Failed to download ${JSON.stringify(wasm)}

What it means

In the WASM worker (lib/shared/worker.ts:84), `tryToInstantiateModule` fetches the esbuild WebAssembly binary by URL via `fetch(wasm)`. If the response is not ok (`res.ok` is false — any non-2xx status), it throws this error including the JSON-stringified `wasm` value (the URL or module descriptor). This is a download/load failure for the WASM service binary.

Solutions

  1. Verify the `wasmURL` resolves to a 200 response for the WASM file and that the host permits CORS.
  2. Bundle the WASM file locally and pass `wasmURL` pointing to a same-origin asset path.
  3. Pre-fetch the module yourself and pass it via `wasmModule` to avoid esbuild's fetch entirely.
  4. Check network/CSP policies (connect-src) allow the WASM origin.

Example fix

// before
await esbuild.initialize({ wasmURL: 'https://broken.cdn/esbuild.wasm' });
// after — host locally / preloaded
await esbuild.initialize({ wasmURL: '/assets/esbuild.wasm' });
// or
const mod = await WebAssembly.compile(await (await fetch('/assets/esbuild.wasm')).arrayBuffer());
await esbuild.initialize({ wasmModule: mod });
Defensive patterns

Strategy: retry

Validate before calling

async function loadWasmModule(url: string): Promise<WebAssembly.Module> {
  let res = await fetch(url);
  if (!res.ok) throw new Error(`Failed to download ${JSON.stringify(url)} (status ${res.status})`);
  return WebAssembly.compile(await res.arrayBuffer());
}
const wasmModule = await loadWasmModule('/assets/esbuild.wasm');
await esbuild.initialize({ wasmModule });

Try / catch

try {
  await esbuild.initialize({ wasmURL });
} catch (e) {
  if (/Failed to download/.test(String(e.message))) { /* retry from a mirror, verify CORS, or preload wasmModule */ }
  else throw e;
}

Prevention

When it happens

Trigger: Loading esbuild-wasm in a browser/worker where the WASM file URL is wrong, the server returns 404/403/500, the URL points to an unreachable host, or a CSP/network policy blocks the fetch.

Common situations: Misconfigured `wasmURL`/`wasmModule` option; serving the `.wasm` file from a CDN that rate-limits or is unreachable; bundler rewrites that break the asset URL; offline or air-gapped browser; CORS restrictions on the hosting origin.

Related errors


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/871bad35dd778c3e. Report an issue: GitHub.

Appendix: source

Thrown at lib/shared/worker.ts:90

    instance => {
      postMessage(null)
      go.run(instance)
    },
    error => {
      postMessage(error)
    },
  )

  return go
}

async function tryToInstantiateModule(wasm: WebAssembly.Module | string, go: Go): Promise<WebAssembly.Instance> {
  if (wasm instanceof WebAssembly.Module) {
    return WebAssembly.instantiate(wasm, go.importObject)
  }

  const res = await fetch(wasm)
  if (!res.ok) throw new Error(`Failed to download ${JSON.stringify(wasm)}`)

  // Attempt to use the superior "instantiateStreaming" API first
  if ('instantiateStreaming' in WebAssembly && /^application\/wasm($|;)/i.test(res.headers.get('Content-Type') || '')) {
    const result = await WebAssembly.instantiateStreaming(res, go.importObject)
    return result.instance
  }

  // Otherwise, fall back to the inferior "instantiate" API
  const bytes = await res.arrayBuffer()
  const result = await WebAssembly.instantiate(bytes, go.importObject)
  return result.instance
}

View on GitHub (pinned to f6058f8364)