Hmbown/CodeWhale · warning · Error
The practice Apply button changed. Run the check again.
Error message
The practice Apply button changed. Run the check again.
What it means
Identical guard to the text-field one, but for the 'Apply' button: after typing, the check re-resolves the button's AX record and throws if the live UI no longer contains it. It indicates the snapshot of the Apply button went stale between get_app_state and the second resolve_element call.
Solutions
- Re-run the background check to take fresh AX snapshots.
- Reduce desktop churn (no window/focus changes) while the check runs.
- If deterministic, verify the practice app's Apply button still exists post-typing and report an app bug if it disappears.
Defensive patterns
Strategy: retry
Try / catch
try {
await runBackgroundCheck({ bundle });
} catch (e) {
if (String(e.message).includes("Apply button changed")) {
return runBackgroundCheck({ bundle }); // stale AX snapshot — one retry
}
throw e;
} Prevention
- Avoid UI churn (window moves, refocus) during the check so AX paths stay valid.
- Retry once on stale-element errors; snapshots go stale transiently.
- File an app bug if the Apply button deterministically disappears after typing.
When it happens
Trigger: In runBackgroundCheck, call('resolve_element', { app_ref: { pid: child.pid }, windowIndex: apply.windowIndex, path: apply.path }) returns { found: false } after typing the phrase.
Common situations: The practice window's layout re-indexed after text entry (button moved), a slow UI that rebuilt the view during typing, or window reordering between steps.
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
- The practice text field changed. Run the check again.
- element press was not acknowledged
- The practice controls could not be read. Check…
- Agent continuation target is no longer retained
- Agent not found
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e82755e77e3896f9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/app/background-check.mjs:71
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." };
} finally {
clearTimeout(timer);
try { await closeSession(sessionId); }
finally {
if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM");
fs.rmSync(scratch, { recursive: true, force: true });View on GitHub (pinned to 73e0f67d83)