{"record":{"id":"94b75d0cf86a415a","repo":"Hmbown/CodeWhale","slug":"the-observed-application-did-not-provide-an-exact-process","errorCode":null,"errorMessage":"The observed application did not provide an exact process identity for OCR","messagePattern":"The observed application did not provide an exact process identity for OCR","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":958,"sourceCode":"      if (!Number.isSafeInteger(window_id) || window_id < 0) {\n        throw Object.assign(new ExecError(\"set_window_frame needs window_id (a non-negative window index from list_windows)\"), { code: \"bad_args\" });\n      }\n      const r = await native(\"set_window_frame\", { app_ref, window_id, frame });\n      return { ...r, verified: r?.verified === true, note: r?.note ?? \"the after frame is the app's own readback; cross-check with list_windows before relying on it\" };\n    },\n    list_windows: listWindows,\n    open_application: openApplication,\n    get_app_state: async ({ app_ref, detail, depth, window_id, include_ocr = false, ocr_region } = {}) => {\n      const t0 = Date.now();\n      const t = await native(\"get_app_state\", { app_ref: app_ref === undefined ? state.inputApp ?? undefined : app_ref, detail, window_id });\n      if (process.env.CODEWHALE_CU_DEBUG_OBSERVE) console.error(`observe ${Date.now() - t0}ms elements=${t.elements?.length} truncated=${t.truncated}`);\n      if (!t.found) throw new ExecError(\"application not found — call list_apps for exact names/pids\");\n      if (include_ocr) {\n        // Resolve once through AX, then capture only that exact application's\n        // selected window. A changing foreground cannot redirect this image.\n        let raster;\n        try {\n          if (!Number.isSafeInteger(t.pid) || t.pid <= 0) throw new ExecError(\"The observed application did not provide an exact process identity for OCR\");\n          if ((await native(\"input_capabilities\"))?.window_ocr !== 1) throw new ExecError(\"The native helper needs an update for selected-window text recognition\");\n          // PNG here, against the JPEG default: this raster is fed to text\n          // recognition, not to a viewer, and lossless glyph edges are what\n          // Vision reads. A single window is small enough that the size the\n          // JPEG default exists to solve does not arise.\n          const ocrDir = path.join(recordingsDir(), \"captures\");\n          fs.mkdirSync(ocrDir, { recursive: true });\n          raster = await screenshot({\n            ...(ocr_region\n              ? { region: ocr_region }\n              : { app_ref: { pid: t.pid, ...(t.bundle_id ? { bundle_id: t.bundle_id } : {}) }, window_id }),\n            path: path.join(ocrDir, `ocr-${crypto.randomBytes(4).toString(\"hex\")}.png`),\n          });\n          const ocr = await native(\"recognize_text\", { file: raster.file });\n          if (ocr?.status === \"ok\" && ocr.pixels?.w === raster.pixels.w && ocr.pixels?.h === raster.pixels.h && Array.isArray(ocr.blocks)) {\n            t.ocr = { ...ocr, raster, blocks: ocr.blocks.map(block => ({ ...block, target: {\n              type: \"coordinate\", x: Math.floor(block.bounds.x + block.bounds.w / 2), y: Math.floor(block.bounds.y + block.bounds.h / 2),\n            } })) };","sourceCodeStart":940,"sourceCodeEnd":976,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L940-L976","documentation":"This error is thrown by the macOS computer-use backend in darwin.mjs when OCR of a specific application's window is requested (include_ocr) but the application resolved through the Accessibility (AX) API has no usable process ID. The backend captures only the exact application identified by pid so a changing foreground window cannot redirect the image; without a positive safe-integer pid it refuses to guess. It is a deliberate guard against OCR-ing the wrong window.","triggerScenarios":"Calling the screenshot/capture path with include_ocr=true after the AX lookup returned an app entry whose pid is undefined, 0, negative, or not a safe integer (checked as !Number.isSafeInteger(t.pid) || t.pid <= 0).","commonSituations":"Targeting a system process or app whose AX entry exposes no pid; using a name-based app reference that resolved loosely; running against sandboxed or partially accessible apps; stale AX metadata after an app restarted.","solutions":["Call list_apps and pick an entry with an explicit positive numeric pid, then pass that exact pid/name reference to the capture call.","Re-open or re-resolve the target with open_application so the backend gets a fresh AX identity before requesting OCR.","If the app genuinely has no pid, request a plain screenshot (include_ocr=false) and run OCR on the full capture instead."],"exampleFix":"// before\nawait session.capture({ app: 'Finder', include_ocr: true }); // app entry lacks pid\n// after\nconst apps = await session.list_apps();\nconst finder = apps.find(a => a.name === 'Finder' && a.pid > 0);\nawait session.capture({ app: finder.name, pid: finder.pid, include_ocr: true });","handlingStrategy":"validation","validationCode":"const app = await session.list_apps().then(a => a.find(x => x.name === appName));\nif (!app || !Number.isSafeInteger(app.pid) || app.pid <= 0) {\n  throw new Error(`cannot OCR ${appName}: no valid pid`);\n}","typeGuard":"const hasValidPid = (app) => app != null && Number.isSafeInteger(app.pid) && app.pid > 0;","tryCatchPattern":"try {\n  await session.capture({ app, include_ocr: true });\n} catch (e) {\n  if (String(e.message).includes('exact process identity')) {\n    await session.capture({ app, include_ocr: false }); // full-frame fallback\n  } else throw e;\n}","preventionTips":["Always resolve targets through list_apps and require a positive pid before OCR calls.","Re-resolve the app after it restarts; AX identities go stale.","Treat system/daemon processes as non-OCR-able targets."],"tags":["macos","ocr","accessibility","process-identity"],"backgroundTag":"missing-required-argument","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}