{"record":{"id":"87ebb68afa482d34","repo":"Hmbown/CodeWhale","slug":"native-screen-recorder-cannot-own-its-client-lifetime-update","errorCode":null,"errorMessage":"native screen recorder cannot own its client lifetime; update Computer Use before recording","messagePattern":"native screen recorder cannot own its client lifetime; update Computer Use before recording","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"critical","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":639,"sourceCode":"    // 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;\n    try {\n      await new Promise((resolve, reject) => {\n        abort = () => { requestRecordingStop(recording); reject(Object.assign(new ExecError(\"computer request cancelled\"), { code: \"cancelled\" })); };","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L621-L657","documentation":"Before spawning the native helper recorder, the backend queries input_capabilities and requires record_owner_pipe === 1, i.e. the installed native Computer Use component supports handing recorder client-lifetime ownership through a pipe. Older helper builds lack this handshake, so recording is refused with an upgrade instruction rather than risking orphaned or mis-owned recorder processes.","triggerScenarios":"Running the darwin backend against an outdated native Computer Use helper binary whose input_capabilities reports no record_owner_pipe support; a partially updated install where the JS backend is newer than the bundled native helper.","commonSituations":"Upgrading the TUI/plugin but not the native helper; a stale helper cached at ~/Library or another install location; rolling back the plugin while keeping a newer/older helper.","solutions":["Update the Computer Use native component to the version matching this backend, then retry.","Verify with the helper's input_capabilities that record_owner_pipe is 1.","If update is not possible, avoid app/window record on this machine or capture with screenshot instead.","Check that no stale older helper binary is earlier on PATH / in the plugin's helper lookup location."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await record({ app_ref }) } catch (e) {\n  if (String(e.message).includes(\"cannot own its client lifetime\")) {\n    // native helper is outdated; surface an upgrade instruction to the user\n    console.error(\"Update the Computer Use native component before recording.\");\n  } else throw e;\n}","preventionTips":["Keep the native Computer Use helper and the JS backend versions in lockstep; update both together.","Check input_capabilities().record_owner_pipe === 1 before offering record actions.","Avoid record calls on machines with known-stale helper installs; use screenshot instead."],"tags":["macos","recording","version-compatibility"],"backgroundTag":"unsupported-operation","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"}