schollz/croc · error · Error

croc WASM did not initialize

Error message

croc WASM did not initialize

What it means

The worker instantiated the Go wasm module and called go.run(instance), then polled self.crocWasm for up to 1000ms (100 attempts x 10ms). If the Go runtime never registers the global crocWasm object within that window, initialization is declared failed. This is a readiness-timeout, not proof the wasm is broken: slow devices, main-thread contention, or a panic inside Go's init path can all exceed the 1-second budget.

Source

Thrown at web/public/croc-worker.js:21

let ready;

function initialize() {
  if (ready) return ready;
  ready = (async () => {
    importScripts(new URL("./wasm_exec.js", self.location.href).href);
    const go = new Go();
    const response = await fetch(new URL("./croc.wasm", self.location.href));
    if (!response.ok) {
      throw new Error(`Could not load croc.wasm (${response.status})`);
    }
    const bytes = await response.arrayBuffer();
    const { instance } = await WebAssembly.instantiate(bytes, go.importObject);
    void go.run(instance);
    for (let attempts = 0; !self.crocWasm && attempts < 100; attempts += 1) {
      await new Promise((resolve) => setTimeout(resolve, 10));
    }
    if (!self.crocWasm) {
      throw new Error("croc WASM did not initialize");
    }
  })();
  return ready;
}

function transferables(value, output = []) {
  if (value instanceof Uint8Array) {
    output.push(value.buffer);
  } else if (value && typeof value === "object") {
    for (const child of Object.values(value)) transferables(child, output);
  }
  return output;
}

self.addEventListener("message", async (event) => {
  const { id, method, args = [] } = event.data;
  try {
    await initialize();

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Reproduce with devtools: check the worker console for a Go panic that explains why crocWasm was never registered
  2. Regenerate croc.wasm and wasm_exec.js from the same Go toolchain so their ABI matches
  3. If startup is just slow, raise the poll budget (more attempts or longer interval) before giving up
  4. Reload the page / recreate the worker to rule out a one-off scheduling stall

Example fix

// before (croc-worker.js)
for (let attempts = 0; !self.crocWasm && attempts < 100; attempts += 1) {
  await new Promise((resolve) => setTimeout(resolve, 10));
}

// after: allow up to ~15s for slow devices
for (let attempts = 0; !self.crocWasm && attempts < 1500; attempts += 1) {
  await new Promise((resolve) => setTimeout(resolve, 10));
}
Defensive patterns

Strategy: retry

Try / catch

// Worker startup: terminate and respawn the worker once on init timeout
try {
  await rpc.call("ping");
} catch (e) {
  if (e.message === "croc WASM did not initialize" && !retriedOnce) {
    worker.terminate();
    spawnWorker();
    retriedOnce = true;
    return retry();
  }
  throw e;
}

Prevention

When it happens

Trigger: Running on low-powered hardware or under heavy CPU throttling where Go's runtime startup plus package init takes longer than 1s; a Go-side panic during initialization that silently prevents crocWasm from being set; wasm_exec.js version mismatch with the compiled croc.wasm so go.run never completes.

Common situations: First load on mobile browsers with cold caches; CI headless-browser tests under CPU throttling; rebuilding croc.wasm with a different Go version without updating wasm_exec.js.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/0e6f591594d0ce71. Report an issue: GitHub.