{"record":{"id":"a98134423d128834","repo":"Hmbown/CodeWhale","slug":"coordinates-must-be-finite-numbers-win32","errorCode":null,"errorMessage":"coordinates must be finite numbers","messagePattern":"coordinates must be finite numbers","errorType":"validation","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/win32.mjs","lineNumber":594,"sourceCode":"    recordingStart: async () => {\n      throw Object.assign(new ExecError(\"Recording is unavailable on this platform until the recorder has session-owned cleanup. Use screenshots instead.\"), { code: \"owned_recording_unavailable\" });\n    },\n    recordingStop: async ({ id }) => { throw new ExecError(`unknown recording \"${id}\"`); },\n    recordingStatus: ({ id }) => ({ id, running: false }),\n    recordingList: async () => {\n      const dir = recordingsDir();\n      const out = fs.existsSync(dir)\n        ? fs.readdirSync(dir).filter((f) => /\\.mp4$/i.test(f)).map((f) => {\n            const st = fs.statSync(path.join(dir, f));\n            return { file: path.join(dir, f), bytes: st.size, modifiedAt: st.mtime.toISOString() };\n          }).sort((a, b) => b.modifiedAt.localeCompare(a.modifiedAt)).slice(0, 50)\n        : [];\n      return { dir, recordings: out, running: [] };\n    },\n  };\n\n  async function clickAt(button, x, y, clicks) {\n    if (!Number.isFinite(Number(x)) || !Number.isFinite(Number(y))) throw new ExecError(\"coordinates must be finite numbers\");\n    const flags = button === 1 ? \"RIGHTDOWN, RIGHTUP\" : button === 2 ? \"MIDDLEDOWN, MIDDLEUP\" : \"LEFTDOWN, LEFTUP\";\n    const seq = [];\n    for (let i = 0; i < clicks; i++) seq.push(`[User32]::mouse_event([User32]::${flags.split(\",\")[0].trim()}, 0, 0, 0, [UIntPtr]::Zero); Start-Sleep -Milliseconds 40; [User32]::mouse_event([User32]::${flags.split(\",\")[1].trim()}, 0, 0, 0, [UIntPtr]::Zero); Start-Sleep -Milliseconds 60;`);\n    const held = button === 1 ? \"RIGHT\" : button === 2 ? \"MIDDLE\" : \"LEFT\";\n    throwIfAborted();\n    heldButtons.add(held);\n    try {\n    await withUser32(`[User32]::SetCursorPos(${Math.round(x)}, ${Math.round(y)}) | Out-Null;\nStart-Sleep -Milliseconds 60;\n${seq.join(\"\\n\")}\nWrite-Output '{\"ok\": true}';`, { timeoutMs: 20_000 });\n    heldButtons.delete(held);\n    return { action_sent: true, at: { x: Number(x), y: Number(y) }, button, clicks };\n    } finally { await releaseInput({ buttons: [held], keys: [] }); }\n  }\n}\n\nexport default { create };","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/win32.mjs#L576-L612","documentation":"clickAt validates its x/y coordinates with Number.isFinite before building the PowerShell mouse_event script. Non-finite coordinates (NaN, Infinity, undefined, non-numeric strings that coerce to NaN) throw this error immediately, before any input is injected. It is a pure input-validation guard protecting Windows' native input path.","triggerScenarios":"Calling clickAt (directly or via left_click/double_click/right_click) with target.x or target.y that is undefined, null, NaN, Infinity, or a non-numeric string — typically from a malformed detection result or a JSON payload missing coordinates.","commonSituations":"An upstream vision/OCR step returned no match so x/y were never assigned; destructuring a click point with the wrong key names; screen-coordinate scaling math dividing by zero to produce Infinity.","solutions":["Validate coordinates before clicking: ensure both are finite numbers (Number.isFinite(Number(x)) mirrors the check).","Fix the coordinate source — check that the detection step actually produced a match before dispatching a click.","Correct key names when destructuring (e.g. { x, y } vs { left, top }) so the right fields are passed.","Clamp or reject out-of-range/scaled values before they reach the backend."],"exampleFix":"// before\nawait backend.left_click({ target: { x: match?.cx, y: match?.cy } });\n// after\nconst x = Number(match?.cx), y = Number(match?.cy);\nif (!Number.isFinite(x) || !Number.isFinite(y)) throw new Error('no click target resolved');\nawait backend.left_click({ target: { x, y } });","handlingStrategy":"validation","validationCode":"function assertClickablePoint(p) {\n  const x = Number(p?.x), y = Number(p?.y);\n  if (!Number.isFinite(x) || !Number.isFinite(y))\n    throw new Error(`click target unresolved: ${JSON.stringify(p)}`);\n  return { x, y };\n}","typeGuard":"const isFinitePoint = (p) =>\n  p != null && Number.isFinite(Number(p.x)) && Number.isFinite(Number(p.y));","tryCatchPattern":"try {\n  await backend.left_click({ target: point });\n} catch (e) {\n  if (e.message === 'coordinates must be finite numbers') {\n    console.warn('detection returned no point; skipping click', point);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Validate detection output (x/y present and finite) before every click.","Check for null matches from vision/OCR steps instead of destructuring undefined.","Guard scaling math against divide-by-zero producing Infinity.","Keep coordinate keys consistent ({x,y} vs {left,top}) across your pipeline."],"tags":["validation","coordinates","input","windows"],"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"}