Hmbown/CodeWhale · error · Error
The practice window screenshot could not be verified. Check…
Error message
The practice window screenshot could not be verified. Check Screen Recording permission.
What it means
The final verification screenshots the practice window and asserts the capture is attributable and non-empty: capture.app_ref.pid must equal the practice child's pid and pixel dimensions must be present. When they are not, the screenshot pipeline could not actually capture the window — on macOS this is the signature of missing Screen Recording (TCC) permission, so the capture returns empty or falls back to something else.
Solutions
- Grant Screen Recording permission (System Settings > Privacy & Security > Screen Recording) to the process running the check, then restart it and retry.
- Confirm the practice app is still running at screenshot time (no early exit).
- If permission is granted and it still fails, inspect the screenshot tool's returned app_ref/pixels in logs and file a computer-use plugin issue.
Example fix
// before
await runBackgroundCheck({ bundle }); // Screen Recording not granted
// after
// Grant Screen Recording to the host process first, restart it, then:
try {
await runBackgroundCheck({ bundle });
} catch (e) {
if (String(e.message).includes("Screen Recording")) {
console.error("Grant Screen Recording permission and retry.");
}
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await runBackgroundCheck({ bundle });
} catch (e) {
if (String(e.message).includes("Screen Recording")) {
console.error("Grant Screen Recording permission (System Settings > Privacy & Security), restart the process, retry.");
}
throw e;
} Prevention
- Grant Screen Recording (TCC) permission during first-run setup, before any capture step.
- Restart the host process after granting; existing processes do not pick up new grants.
- Keep the practice window alive until verification completes (no early exit between Apply and screenshot).
When it happens
Trigger: In runBackgroundCheck, the screenshot tool reply has capture.app_ref?.pid !== child.pid or capture.pixels?.w/h falsy, i.e. a zero-sized, empty, or wrong-window capture.
Common situations: Screen Recording permission never granted (or granted to the wrong process), captures silently returning blank frames without permission, or the practice window closing before the screenshot.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- The practice controls could not be read. Check…
- choose app_ref or region, not both
- exited
- display index must be a positive integer
- linux backend needs " " for — install it and retry
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/a60a7a869b67f06d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/app/background-check.mjs:77
}
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)