{"record":{"id":"83cc94236a41bbd3","repo":"Hmbown/CodeWhale","slug":"coordinates-must-be-finite-numbers","errorCode":null,"errorMessage":"coordinates must be finite numbers","messagePattern":"coordinates must be finite numbers","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":361,"sourceCode":"    // Any successful capture (bind, explicit preview, action refresh) starts\n    // the live refresh; the tick itself re-enters this function as a no-op.\n    if (state.previewEnabled && state.inputApp) startPreviewLoop();\n    return { enabled: true, file, app: state.inputApp, pointer: p };\n  }\n\n  // ---------- pointer input ----------\n  // Our qualified raw pointer path uses the shared event tap, which moves\n  // the user's real cursor. Process/window-directed mouse delivery has not\n  // passed the independent fixture. So the pointer path is:\n  //   1. accessibility action on the element under the point (quiet, exact),\n  //   2. otherwise refuse in background mode. Explicit foreground control\n  //      permits a global gesture only when the bound application owns the\n  //      window under the point. Restoring the cursor is not isolation.\n  // Every receipt says which of the two happened.\n  function mouseName(button) { return { left: \"left\", right: \"right\", middle: \"middle\" }[button] ?? \"left\"; }\n\n  function assertInScreen(x, y) {\n    if (!Number.isFinite(x) || !Number.isFinite(y)) throw new ExecError(\"coordinates must be finite numbers\");\n  }\n\n  function buttonCode(button) { return button === \"middle\" ? 2 : button === \"right\" ? 1 : 0; }\n\n  function requireSharedPointer() {\n    if (!state.foregroundInput) throw Object.assign(new ExecError(\"This action needs the shared macOS pointer and was not sent in background mode. Use an accessibility action or a separate computer; foreground control requires exclusive desktop use authorized by the user.\"), { code: \"shared_pointer_required\" });\n  }\n\n  /** Refuse a global gesture whose landing point belongs to another application. */\n  async function assertOwnsPoint(x, y) {\n    if (!state.inputApp) throw new ExecError(\"open_application first to choose which application receives input\");\n    const w = await native(\"window_at_point\", { x, y });\n    if (!w?.found) throw new ExecError(`no window at (${x}, ${y}) — take a fresh screenshot and choose a point inside the target window`);\n    if (w.owner_pid !== state.inputApp.pid) {\n      throw new ExecError(`(${x}, ${y}) is covered by a window owned by ${w.owner_name || \"another application\"} (pid ${w.owner_pid}) — use an accessibility element target or a separate computer; no pointer input was sent`);\n    }\n    return w;\n  }","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L343-L379","documentation":"assertInScreen guards every pointer/coordinate action: x and y must both be finite numbers (screen coordinates). NaN, Infinity, or non-numeric coordinates would otherwise be forwarded to the native helper and produce undefined clicks at arbitrary positions, so they are rejected up front.","triggerScenarios":"Calling a coordinate-based tool (click, move, scroll, drag endpoints) with x or y that is NaN, ±Infinity, undefined, null, or a non-number — usually from parsing screenshot annotations into bad numbers or dividing by zero when scaling coordinates.","commonSituations":"LLM-emitted arguments with missing/garbled coordinates; coordinate scaling math producing NaN (e.g. multiplying undefined); JSON payloads where coordinates arrive as strings like \"120\" that later math turns into NaN; empty screenshot annotations yielding undefined points.","solutions":["Parse coordinates with Number() and validate Number.isFinite(x) && Number.isFinite(y) before calling the tool.","Take a fresh screenshot/observe to get real coordinates instead of reusing ones derived from stale or failed data.","Fix scaling math: guard every multiplication/division that derives x/y from image-vs-screen scale factors.","If arguments come from a model, tighten the tool schema so x/y are required finite numbers."],"exampleFix":"// before\nconst x = annot.left * scale; // annot.left undefined → NaN\nawait click({ x, y });\n\n// after\nconst x = Number(annot?.left) * scale, y = Number(annot?.top) * scale;\nif (!Number.isFinite(x) || !Number.isFinite(y)) throw new Error(\"bad point\");\nawait click({ x, y });","handlingStrategy":"type-guard","validationCode":"function isPoint(p) { return Number.isFinite(p?.x) && Number.isFinite(p?.y); }\nif (!isPoint(pt)) throw new Error('coordinates must be finite numbers before calling the tool');","typeGuard":"function isFinitePoint(p) {\n  return typeof p === 'object' && p !== null && Number.isFinite(p.x) && Number.isFinite(p.y);\n}","tryCatchPattern":"try {\n  await click({ x, y });\n} catch (e) {\n  if (String(e.message).includes('coordinates must be finite')) {\n    const shot = await screenshot(); // re-derive coordinates from fresh data\n    ({ x, y } = toScreenPoint(shot));\n    await click({ x, y });\n  } else throw e;\n}","preventionTips":["Run Number.isFinite on every coordinate at the boundary where arguments enter your automation code.","Avoid undefined-propagation in scale math: default and validate every scale factor.","Convert model-emitted string coordinates with Number() and reject NaN early.","Enforce a strict JSON schema (type: number) for x/y tool arguments."],"tags":["coordinates","validation","input","nan"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}