Hmbown/CodeWhale · warning · Error

The check was interrupted. You can run it again when ready.

Error message

The check was interrupted. You can run it again when ready.

What it means

The until() helper spins waiting for a condition (app ready, apply event, new samples). If the spawned practice process exits (child.exitCode !== null) or the 15-second AbortController fires while the condition is still unmet, until() throws this error instead of hanging. It means the check was cut short, not that the checked behavior failed.

Solutions

  1. Simply retry runBackgroundCheck() — the message is explicitly designed as a re-runnable interruption.
  2. Check whether the practice app binary launches cleanly outside the check to rule out crashes.
  3. If timeouts are frequent on your hardware, allow more wall time or investigate what slows the app's 'ready' event.

Example fix

// before
await runBackgroundCheck({ bundle }); // may throw on transient interruption

// after
try {
  await runBackgroundCheck({ bundle });
} catch (e) {
  if (String(e.message).includes("interrupted")) {
    await runBackgroundCheck({ bundle }); // one clean retry
  } else throw e;
}
Defensive patterns

Strategy: retry

Try / catch

const MAX_ATTEMPTS = 3;
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
  try {
    return await runBackgroundCheck({ bundle });
  } catch (e) {
    const interrupted = String(e.message).includes("interrupted");
    if (!interrupted || attempt === MAX_ATTEMPTS) throw e;
    await new Promise(r => setTimeout(r, 1000 * attempt));
  }
}

Prevention

When it happens

Trigger: Inside runBackgroundCheck, any await until(...) where the practice child process crashes/exits early, or the 15s timer aborts controller.signal before the predicate becomes true.

Common situations: Slow machines where the app takes longer than 15s to become ready, the practice binary crashing at startup, or the abort timeout firing during a long typing/screenshot step.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/00a7f3f5c6deb34d. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/app/background-check.mjs:35

  const child = spawn(executable, [], { stdio: ["ignore", "pipe", "pipe"] });
  const scratch = fs.mkdtempSync(path.join(os.tmpdir(), "cu-setup-capture-"));
  let ready = false, applied = null, latest = null, buffer = "", spawnError = null;
  child.on("error", error => { spawnError = error; });
  child.stderr.on("data", () => {});
  child.stdout.setEncoding("utf8");
  child.stdout.on("data", chunk => {
    buffer += chunk;
    if (buffer.length > 16_384) { controller.abort(); return; }
    let newline;
    while ((newline = buffer.indexOf("\n")) >= 0) {
      const line = buffer.slice(0, newline); buffer = buffer.slice(newline + 1);
      try { const result = JSON.parse(line); latest = result; if (result.event === "ready") ready = true; if (result.event === "applied") applied = result; } catch { /* Cocoa diagnostics are not receipts. */ }
    }
  });
  async function until(predicate) {
    while (!predicate()) {
      if (spawnError) throw spawnError;
      if (controller.signal.aborted || child.exitCode !== null) throw new Error("The check was interrupted. You can run it again when ready.");
      await delay(40);
    }
  }
  async function call(tool, args = {}) {
    const reply = await handle({ tool, args }, { sessionId, signal: controller.signal, persistentInputOwner: true });
    if (!reply.ok) throw new Error(reply.error.message);
    return reply.data;
  }
  try {
    await until(() => ready);
    await call("open_application", { pid: child.pid, activate: false });
    const state = await call("get_app_state");
    if (demoDirectory) {
      fs.mkdirSync(demoDirectory, { recursive: true });
      // AX can register before WindowServer makes a new window capturable.
      // Retry only this read, before sending any input, within the check limit.
      while (true) {
        try { await call("screenshot", { app_ref: { pid: child.pid }, path: path.join(demoDirectory, "01-ready.png") }); break; }

View on GitHub (pinned to 73e0f67d83)