{"record":{"id":"aed6f9b72c878206","repo":"Hmbown/CodeWhale","slug":"choose-one-available-display-for-recording","errorCode":null,"errorMessage":"choose one available display for recording","messagePattern":"choose one available display for recording","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":636,"sourceCode":"    // app_ref scopes the recording to the app's window rect: resolved once at\n    // start through the same window_info the AX path uses, so a background\n    // window records behind the user's work. The rect is fixed at start —\n    // it does not track later moves or resizes.\n    let window = null;\n    if (app_ref !== undefined || window_id != null) {\n      window = await native(\"window_info\", { app_ref: app_ref === undefined ? state.inputApp ?? undefined : app_ref, window_id });\n      if (!window?.points || !(window.points.w > 0) || !(window.points.h > 0)) throw new ExecError(\"the selected application has no capturable window — call list_windows\");\n      if (region) throw new ExecError(\"choose app_ref or region, not both\");\n      region = [window.points.x, window.points.y, window.points.w, window.points.h];\n    }\n    let disp = display ?? state.activeDisplay;\n    if (window && display == null) {\n      const cx = region[0] + region[2] / 2, cy = region[1] + region[3] / 2;\n      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);\n      if (host) disp = host.index;\n    }\n    const selected = displays.find(d => d.index === disp);\n    if (!selected) throw new ExecError(\"choose one available display for recording\");\n    if (durationSec != null && (!Number.isFinite(durationSec) || durationSec <= 0)) throw new ExecError(\"durationSec must be positive\");\n    const capabilities = await native(\"input_capabilities\");\n    if (capabilities?.record_owner_pipe !== 1) throw new ExecError(\"native screen recorder cannot own its client lifetime; update Computer Use before recording\");\n    const helper = await nativeHelper();\n    throwIfAborted();\n    const child = spawn(helper, [JSON.stringify({ tool: \"record\", args: { file, displayID: selected.id, region, durationSec, owner_pipe: true } })], { stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n    child.stdin.on(\"error\", () => {});\n    const startedAt = new Date().toISOString();\n    let stderr = \"\", output = \"\", ready = false;\n    const completion = new Promise(resolve => {\n      child.once(\"error\", error => resolve({ code: -1, error: error.message }));\n      child.once(\"close\", code => resolve({ code, error: stderr.trim() }));\n    });\n    child.stderr.on(\"data\", chunk => { stderr = (stderr + chunk).slice(-4000); });\n    const recording = { child, completion, pid: child.pid, file, startedAt, mode: \"ScreenCaptureKit\", display: disp };\n    rec.set(id, recording);\n    const signal = currentSignal();\n    let timer, abort;","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L618-L654","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait record({ display: staleIndex });\n// after\nconst displays = await list_displays();\nawait record({ display: displays[0].index });","handlingStrategy":"validation","validationCode":"const displays = await list_displays();\nconst idx = display ?? displays[0]?.index;\nif (!displays.some(d => d.index === idx))\n  throw new Error(`display ${idx} not attached; have [${displays.map(d => d.index)}]`);","typeGuard":"const displayExists = (idx, displays) => displays.some(d => d.index === idx);","tryCatchPattern":"try { await record({ display }) } catch (e) {\n  if (String(e.message).includes(\"choose one available display\")) {\n    const displays = await list_displays();\n    await record({ display: displays[0].index });\n  } else throw e;\n}","preventionTips":["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."],"tags":["macos","recording","display"],"backgroundTag":"resource-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}