{"record":{"id":"cdccf7710e367cc9","repo":"Hmbown/CodeWhale","slug":"no-raster","errorCode":"no_raster","errorMessage":"no screenshot bound on this computer yet — call screenshot first so pixel targets have a frame","messagePattern":"no screenshot bound on this computer yet — call screenshot first so pixel targets have a frame","errorType":"error_code","errorClass":"ServerError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/mcp/server.mjs","lineNumber":176,"sourceCode":"function resolveElement(target, computer) {\n  const stateId = target.state_id ?? latestStateByComputer.get(computer.id);\n  const st = stateId ? appStates.get(stateId) : null;\n  if (!st) throw new ServerError(\"unknown_state\", target.state_id\n    ? `state_id \"${target.state_id}\" is unknown or expired — call get_app_state again`\n    : \"no observation on this computer yet — call get_app_state first\");\n  const el = st.elements[target.index];\n  if (!el) throw new ServerError(\"unknown_element\", `element index ${target.index} is outside state ${stateId} (0..${st.elements.length - 1})`);\n  return { state: st, element: el, stateId };\n}\n\nclass ServerError extends Error {\n  constructor(code, message, extra = null) { super(message); this.code = code; if (extra) this.extra = extra; }\n}\n\n/** Map raster-pixel coordinates to screen points using the bound raster. */\nfunction rasterToPoints(computerId, x, y) {\n  const r = lastRasters.get(computerId);\n  if (!r) throw new ServerError(\"no_raster\", \"no screenshot bound on this computer yet — call screenshot first so pixel targets have a frame\");\n  if (r.pixels?.w != null && r.pixels?.h != null && (x < 0 || y < 0 || x >= r.pixels.w || y >= r.pixels.h)) {\n    throw new ServerError(\"target_outside_raster\", `target (${x},${y}) is outside the bound raster (${r.pixels.w}x${r.pixels.h} pixels) — take a fresh screenshot`);\n  }\n  const scale = r.scale && r.scale > 0 ? r.scale : 1;\n  return { x: (r.origin?.x ?? 0) + x / scale, y: (r.origin?.y ?? 0) + y / scale };\n}\n\n/**\n * Normalize a target into backend form: points for coordinates, resolved\n * element for elements. Element targets are revalidated against the live\n * backend when a resolver is available: stale elements throw `element_stale`,\n * moved-but-identical elements are re-aimed at their fresh center\n * (sink.reacquired = true so the receipt can say target_reacquired).\n */\nasync function normalizeTarget(computer, target, kind, resolve, sink) {\n  if (target?.type === \"coordinate\") {\n    if (target.space === \"screen\") {\n      if (!Number.isFinite(target.x) || !Number.isFinite(target.y)) {","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/mcp/server.mjs#L158-L194","documentation":"rasterToPoints converts raster-pixel coordinates to screen points using a per-computer bound raster (the last screenshot's pixel size, scale factor, and origin). When no screenshot has been taken on that computer there is no frame to map pixels against, so the server throws code \"no_raster\" rather than assuming a 1:1 mapping that would click in the wrong place.","triggerScenarios":"A coordinate target with target.space === \"raster\" (or unset, which defaults to raster space in normalizeTarget) sent to a computer where lastRasters has no entry — no screenshot call has happened in this session, or the raster binding was lost via restart/reset.","commonSituations":"Replaying a recorded raster-coordinate script against a fresh server or new computer; an agent switches computers and forgets to re-screenshot on the new one; assuming raster space works without a screenshot because screen-space coordinates do.","solutions":["Take a screenshot on that computer first — it binds the raster that pixel targets are mapped through.","Use target.space === \"screen\" with screen-point coordinates if you don't need pixel addressing.","Confirm the computer id matches the one you screenshotted (the raster is keyed per computer).","After a server restart, re-screenshot before any raster-targeted action."],"exampleFix":"// before\nawait click({ computerId, target: { type: \"coordinate\", x: 500, y: 300 } }); // raster by default, no frame\n\n// after\nawait screenshot(computerId); // binds the raster\nawait click({ computerId, target: { type: \"coordinate\", space: \"raster\", x: 500, y: 300 } });","handlingStrategy":"fallback","validationCode":"if (target.space !== \"screen\" && !hasBoundRaster(computerId)) await screenshot(computerId);","typeGuard":"const canUseRaster = (computerId) => lastRasters.has(computerId);","tryCatchPattern":"try {\n  return await click({ computerId, target: { type: \"coordinate\", space: \"raster\", x, y } });\n} catch (e) {\n  if (e.code === \"no_raster\") {\n    await screenshot(computerId);\n    return await click({ computerId, target: { type: \"coordinate\", space: \"raster\", x, y } });\n  }\n  throw e;\n}","preventionTips":["Screenshot each computer before sending any raster-space coordinates.","Prefer screen-space targets when your coordinates don't derive from a screenshot.","Re-screenshot after restarts or when switching between computers.","Track raster binding per computer id in your automation state."],"tags":["coordinates","precondition","screenshot","mcp"],"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-23T08:17:48.524Z"}