Hmbown/CodeWhale · error · ServerError
target_outside_raster
target_outside_raster
Error message
target (${x},${y}) is outside the bound raster (${r.pixels.w}x${r.pixels.h} pixels) — take a fresh screenshot What it means
When a bound raster exists and records its pixel dimensions, rasterToPoints validates the requested pixel coordinates against them and throws code "target_outside_raster" if x or y is negative or beyond the captured width/height. This prevents silently clamping or wrapping coordinates into an unintended on-screen point; the message names the raster size and suggests re-screenshotting.
Solutions
- Take a fresh screenshot and recompute the pixel coordinates from the new raster.
- Validate 0 <= x < width and 0 <= y < height against the screenshot's reported pixel size before sending.
- If the display resolution changed, re-derive coordinates for the new geometry instead of rescaling old ones.
- Use screen-space coordinates if your points come from a source independent of the raster.
Example fix
// before
await click({ computerId, target: { type: "coordinate", space: "raster", x: 2400, y: 100 } }); // raster is 1920 wide
// after
const shot = await screenshot(computerId);
const x = Math.min(2400 * (shot.pixels.w / 2560), shot.pixels.w - 1);
await click({ computerId, target: { type: "coordinate", space: "raster", x, y: 100 } }); Defensive patterns
Strategy: validation
Validate before calling
const { w, h } = boundRaster(computerId).pixels;
if (!(x >= 0 && x < w && y >= 0 && y < h)) throw new Error(`target (${x},${y}) outside raster ${w}x${h}`); Type guard
const inRaster = (r, x, y) => r?.pixels?.w != null && r?.pixels?.h != null && x >= 0 && y >= 0 && x < r.pixels.w && y < r.pixels.h;
Try / catch
try {
return await click({ computerId, target: { type: "coordinate", space: "raster", x, y } });
} catch (e) {
if (e.code === "target_outside_raster") {
const shot = await screenshot(computerId);
const { x: nx, y: ny } = recomputeFor(shot, x, y);
return await click({ computerId, target: { type: "coordinate", space: "raster", x: nx, y: ny } });
}
throw e;
} Prevention
- Derive pixel coordinates from the same screenshot you bound, not an older one.
- Clamp or bounds-check against the screenshot's reported width/height before sending.
- Recompute coordinates after any display/VM resolution change.
- Watch for subtraction-based math that can produce negatives.
When it happens
Trigger: Coordinate target in raster space where x < 0 || y < 0 || x >= pixels.w || y >= pixels.h: coordinates computed from a different-resolution screenshot, a scaled-up image the model read pixels from, or negative values from a bad subtraction.
Common situations: Display resolution changed between screenshot and action (window moved to another monitor, VM resized); using pixel coordinates from an image viewer that upscaled the screenshot; arithmetic on coordinates that underflows below zero.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- no_raster
- bad_target
- unknown_element
- A managed, project or plugin connector already uses this…
- Absolute path should not warn
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d02eed5401b8075d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/mcp/server.mjs:178
const st = stateId ? appStates.get(stateId) : null;
if (!st) throw new ServerError("unknown_state", target.state_id
? `state_id "${target.state_id}" is unknown or expired — call get_app_state again`
: "no observation on this computer yet — call get_app_state first");
const el = st.elements[target.index];
if (!el) throw new ServerError("unknown_element", `element index ${target.index} is outside state ${stateId} (0..${st.elements.length - 1})`);
return { state: st, element: el, stateId };
}
class ServerError extends Error {
constructor(code, message, extra = null) { super(message); this.code = code; if (extra) this.extra = extra; }
}
/** Map raster-pixel coordinates to screen points using the bound raster. */
function rasterToPoints(computerId, x, y) {
const r = lastRasters.get(computerId);
if (!r) throw new ServerError("no_raster", "no screenshot bound on this computer yet — call screenshot first so pixel targets have a frame");
if (r.pixels?.w != null && r.pixels?.h != null && (x < 0 || y < 0 || x >= r.pixels.w || y >= r.pixels.h)) {
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`);
}
const scale = r.scale && r.scale > 0 ? r.scale : 1;
return { x: (r.origin?.x ?? 0) + x / scale, y: (r.origin?.y ?? 0) + y / scale };
}
/**
* Normalize a target into backend form: points for coordinates, resolved
* element for elements. Element targets are revalidated against the live
* backend when a resolver is available: stale elements throw `element_stale`,
* moved-but-identical elements are re-aimed at their fresh center
* (sink.reacquired = true so the receipt can say target_reacquired).
*/
async function normalizeTarget(computer, target, kind, resolve, sink) {
if (target?.type === "coordinate") {
if (target.space === "screen") {
if (!Number.isFinite(target.x) || !Number.isFinite(target.y)) {
throw new ServerError("bad_target", "screen coordinates must be finite numbers");
}View on GitHub (pinned to 73e0f67d83)