schollz/croc · error · Error

${method} failed

Error message

${method} failed

What it means

The worker dispatched a method call on the crocWasm bridge and the Go side returned {ok: false} without a specific error string, so the worker substitutes the generic '<method> failed'. It is the catch-all for any Go-level failure inside the requested WASM function (hashing, PAKE, encryption, code generation) that did not produce its own message. The real cause is only distinguishable by which method was invoked.

Source

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

}

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();
    const fn = self.crocWasm[method];
    if (typeof fn !== "function") throw new Error(`Unknown WASM method: ${method}`);
    const response = fn(...args);
    if (!response.ok) throw new Error(response.error || `${method} failed`);
    self.postMessage({ id, result: response.value }, transferables(response.value));
  } catch (error) {
    self.postMessage({
      id,
      error: error instanceof Error ? error.message : String(error),
    });
  }
});

void initialize().catch((error) => {
  self.postMessage({
    id: 0,
    error: error instanceof Error ? error.message : String(error),
  });
});

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Identify which WASM method was called (it appears in the message) and validate its inputs before dispatch
  2. Check that byte arrays are non-detached and of the expected length before posting to the worker
  3. Ensure one-shot handles (hashInit/pakeInit results) are not reused after an error or retry
  4. Inspect the Go side of the bridge: add or surface response.error so the real failure text reaches the caller

Example fix

// before: caller posts a possibly detached buffer
worker.postMessage({ id, method: "encrypt", args: [data.buffer, key] });

// after: validate inputs and re-copy before dispatch
if (data.byteLength === 0) throw new Error("empty plaintext");
worker.postMessage({ id, method: "encrypt", args: [new Uint8Array(data), key] });
Defensive patterns

Strategy: try-catch

Validate before calling

// Reject detached/empty buffers before posting to the worker
function assertBytes(b, name) {
  if (!(b instanceof Uint8Array) || b.byteLength === 0) throw new Error(`${name} must be a non-empty Uint8Array`);
  if (b.buffer.byteLength === 0) throw new Error(`${name} buffer is detached`);
}

Try / catch

// RPC caller: wrap each call, annotate with the method name for diagnosis
try {
  return await rpc.call(method, args);
} catch (e) {
  throw new Error(`${method}: ${e.message}`, { cause: e });
}

Prevention

When it happens

Trigger: Calling engine methods with malformed inputs, e.g. pakeUpdate with a handle that was already consumed; passing empty or wrong-length Uint8Arrays to crypto functions; a Go panic recovered into the generic ok:false result; memory pressure aborting the wasm computation.

Common situations: Sending detached ArrayBuffers to the worker (they were transferred in a previous postMessage); reusing one-shot PAKE handles across retries; Safari iOS wasm memory limits on large hashing operations.

Related errors


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