Hmbown/CodeWhale · warning · Error

The practice text field changed. Run the check again.

Error message

The practice text field changed. Run the check again.

What it means

The check resolves the located 'Practice text' AX element to a concrete backend target via resolve_element. If the reply says found: false, the element record captured moments earlier no longer matches the live UI — the field's AX path or window changed between snapshot and resolution. The error asks you to rerun so a fresh snapshot is taken.

Solutions

  1. Re-run the background check — a fresh state snapshot usually resolves the element successfully.
  2. Run the check on a quiet desktop (no other apps opening/closing) so AX indices stay stable.
  3. If it reproduces every time, capture app logs and report an AX indexing bug against the practice app.
Defensive patterns

Strategy: retry

Try / catch

try {
  await runBackgroundCheck({ bundle });
} catch (e) {
  if (String(e.message).includes("practice text field changed")) {
    return runBackgroundCheck({ bundle }); // stale AX snapshot — one retry
  }
  throw e;
}

Prevention

When it happens

Trigger: In runBackgroundCheck, call('resolve_element', { app_ref: { pid: child.pid }, windowIndex: entry.windowIndex, path: entry.path }) returns { found: false } after the text field was found in the state snapshot.

Common situations: The practice window moved, reopened, or re-indexed between get_app_state and resolve_element; UI animations delaying layout; another window stealing focus and changing window order.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

    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; }
        catch (error) {
          if (controller.signal.aborted || !error.message.includes("not capturable")) throw error;
          await delay(100, undefined, { signal: controller.signal });
        }
      }
    }
    const entry = state.elements.find(element => element.role === "AXTextField" && element.label === "Practice text");
    const apply = state.elements.find(element => element.role === "AXButton" && element.label === "Apply");
    if (!entry || !apply) throw new Error("The practice controls could not be read. Check Accessibility permission and retry.");
    // Backend targets are resolved AX records, using the exact state index.
    const focus = await call("resolve_element", { app_ref: { pid: child.pid }, windowIndex: entry.windowIndex, path: entry.path });
    if (!focus.found) throw new Error("The practice text field changed. Run the check again.");
    await call("left_click", { target: { ...focus.element, type: "element", app_ref: { pid: child.pid } } });
    const phrase = "Background check complete 🐋";
    await call("type", { text: phrase });
    if (demoDirectory) await call("screenshot", { app_ref: { pid: child.pid }, path: path.join(demoDirectory, "02-entered.png") });
    const button = await call("resolve_element", { app_ref: { pid: child.pid }, windowIndex: apply.windowIndex, path: apply.path });
    if (!button.found) throw new Error("The practice Apply button changed. Run the check again.");
    await call("left_click", { target: { ...button.element, type: "element", app_ref: { pid: child.pid } } });
    await until(() => applied);
    if (applied.value !== phrase) throw new Error("The text received by the practice window did not match. Check the app log and retry.");
    const capture = await call("screenshot", { app_ref: { pid: child.pid }, path: path.join(scratch, "practice.png") });
    if (demoDirectory) fs.copyFileSync(capture.file, path.join(demoDirectory, "03-verified.png"));
    if (capture.app_ref?.pid !== child.pid || !capture.pixels?.w || !capture.pixels?.h) throw new Error("The practice window screenshot could not be verified. Check Screen Recording permission.");
    const count = latest.samples;
    await until(() => latest.samples > count);
    const isolated = latest.samples > 0 && latest.pointerChanges === 0 && latest.foregroundChanges === 0;
    return { ok: isolated, edited: true, screenshot: true, samples: latest.samples, pointerChanges: latest.pointerChanges, foregroundChanges: latest.foregroundChanges,
      message: isolated ? "Text entered, Apply verified and the practice window captured. Your foreground app and pointer stayed unchanged."
        : "Edit and screenshot verified. Your app or pointer moved during the check, so background isolation is inconclusive." };

View on GitHub (pinned to 73e0f67d83)