Hmbown/CodeWhale · error · ExecError
choose one available display for recording
Error message
choose one available display for recording
What it means
After resolving the effective display (explicit `display`, remembered activeDisplay, or host display of the window rect), the record action requires that display to exist in the current display list. If the resolved index matches no attached display, recording cannot proceed and the library throws.
Solutions
- Refresh with list_displays and pass one of the returned `index` values as display.
- Clear/omit the display option so recording falls back to a currently attached display.
- Update any persisted activeDisplay state after monitor changes.
Example fix
// before
await record({ display: staleIndex });
// after
const displays = await list_displays();
await record({ display: displays[0].index }); Defensive patterns
Strategy: validation
Validate before calling
const displays = await list_displays();
const idx = display ?? displays[0]?.index;
if (!displays.some(d => d.index === idx))
throw new Error(`display ${idx} not attached; have [${displays.map(d => d.index)}]`); Type guard
const displayExists = (idx, displays) => displays.some(d => d.index === idx);
Try / catch
try { await record({ display }) } catch (e) {
if (String(e.message).includes("choose one available display")) {
const displays = await list_displays();
await record({ display: displays[0].index });
} else throw e;
} Prevention
- Re-run list_displays after any dock/undock or monitor change.
- Clear stale activeDisplay state that may reference a disconnected monitor.
- Pass indexes (not ids) and remember the list is effectively 1-based.
When it happens
Trigger: Calling record({ display: N }) where N is not an index of an attached display; a stale state.activeDisplay referencing a monitor that was disconnected; index 0 passed to a 1-based display list.
Common situations: Undocking a laptop between sessions leaves the old activeDisplay; agents pass display ids instead of indexes; headless adapters present when configured but not at record time.
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
- durationSec must be positive
- native screen recorder cannot own its client lifetime…
- no display ; have [ ]
- the selected application has no capturable window — call…
- application not found — call list_apps for exact names/pids
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/aed6f9b72c878206.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:636
// app_ref scopes the recording to the app's window rect: resolved once at
// start through the same window_info the AX path uses, so a background
// window records behind the user's work. The rect is fixed at start —
// it does not track later moves or resizes.
let window = null;
if (app_ref !== undefined || window_id != null) {
window = await native("window_info", { app_ref: app_ref === undefined ? state.inputApp ?? undefined : app_ref, window_id });
if (!window?.points || !(window.points.w > 0) || !(window.points.h > 0)) throw new ExecError("the selected application has no capturable window — call list_windows");
if (region) throw new ExecError("choose app_ref or region, not both");
region = [window.points.x, window.points.y, window.points.w, window.points.h];
}
let disp = display ?? state.activeDisplay;
if (window && display == null) {
const cx = region[0] + region[2] / 2, cy = region[1] + region[3] / 2;
const host = displays.find(d => d.points && cx >= d.points.x && cx < d.points.x + d.points.w && cy >= d.points.y && cy < d.points.y + d.points.h);
if (host) disp = host.index;
}
const selected = displays.find(d => d.index === disp);
if (!selected) throw new ExecError("choose one available display for recording");
if (durationSec != null && (!Number.isFinite(durationSec) || durationSec <= 0)) throw new ExecError("durationSec must be positive");
const capabilities = await native("input_capabilities");
if (capabilities?.record_owner_pipe !== 1) throw new ExecError("native screen recorder cannot own its client lifetime; update Computer Use before recording");
const helper = await nativeHelper();
throwIfAborted();
const child = spawn(helper, [JSON.stringify({ tool: "record", args: { file, displayID: selected.id, region, durationSec, owner_pipe: true } })], { stdio: ["pipe", "pipe", "pipe"] });
child.stdin.on("error", () => {});
const startedAt = new Date().toISOString();
let stderr = "", output = "", ready = false;
const completion = new Promise(resolve => {
child.once("error", error => resolve({ code: -1, error: error.message }));
child.once("close", code => resolve({ code, error: stderr.trim() }));
});
child.stderr.on("data", chunk => { stderr = (stderr + chunk).slice(-4000); });
const recording = { child, completion, pid: child.pid, file, startedAt, mode: "ScreenCaptureKit", display: disp };
rec.set(id, recording);
const signal = currentSignal();
let timer, abort;View on GitHub (pinned to 73e0f67d83)