Hmbown/CodeWhale · error · ExecError
no screenshot taken yet on this computer — call screenshot…
Error message
no screenshot taken yet on this computer — call screenshot first
What it means
The zoom action crops from the most recent screenshot raster cached in state.lastRaster. If no screenshot has been taken in this session (or no explicit `source` is given), there is no raster to crop and the library throws. A `source` path bypasses this requirement.
Solutions
- Call screenshot() before zoom() in the same session.
- Pass an explicit `source` image path to zoom({ source, region }) instead of relying on the cached raster.
- Re-establish state if the backend was restarted, then screenshot first.
Example fix
// before
await zoom({ region: [0, 0, 100, 100] }); // fresh session
// after
await screenshot();
await zoom({ region: [0, 0, 100, 100] }); Defensive patterns
Strategy: try-catch
Try / catch
try { await zoom({ region }) } catch (e) {
if (String(e.message).includes("no screenshot taken yet")) {
await screenshot();
await zoom({ region });
} else throw e;
} Prevention
- Always screenshot before zoom in the same backend session.
- After any backend restart, treat lastRaster as empty.
- Pass an explicit `source` path when the raster may be from an earlier session.
When it happens
Trigger: Calling zoom({ region }) without first calling screenshot() in the same backend session; after a backend restart/state reset that cleared lastRaster; calling zoom on a fresh connection while the screenshot was taken in a different session.
Common situations: An agent starts a new session and immediately calls zoom assuming previous state; the computer-use backend process was restarted between the screenshot and the zoom call.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- region must be [x, y, w, h] in last-raster pixels
- Agent has no continuable checkpoint to resume from…
- application not found — call list_apps for exact names/pids
- attempt finalization status must be terminal
- background preview capture failed
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/ae1b7bbc374bffee.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:572
state.lastRaster = {
file,
...(window ? { app_ref, window_index: window_id ?? 0 } : {}),
bytes: stat.size,
display: disp ?? 1,
// Region and window rasters describe that rect, not the whole display.
// The PNG header is the pixel ground truth; scale is derived from
// pixels/points below so Retina and mixed-DPI stay exact.
points: window?.points ?? (region ? { x: region[0], y: region[1], w: region[2], h: region[3] } : d?.points ?? null),
pixels: imagePixels(file),
scale: d?.scale ?? 1,
capturedAt: new Date().toISOString(),
};
if (state.lastRaster.points?.w) state.lastRaster.scale = state.lastRaster.pixels.w / state.lastRaster.points.w;
return { ...state.lastRaster, path: file };
}
async function zoom({ source, region, path: outPath }) {
if (!source && !state.lastRaster) throw new ExecError("no screenshot taken yet on this computer — call screenshot first");
const [x, y, w, h] = region;
if (![x, y, w, h].every((n) => Number.isInteger(n) && n >= 0) || !w || !h || x + w > state.lastRaster.pixels.w || y + h > state.lastRaster.pixels.h) throw new ExecError("region must be [x, y, w, h] in last-raster pixels");
const src = source ?? state.lastRaster.file;
const dir = recordingsDir();
fs.mkdirSync(dir, { recursive: true });
const out = outPath || path.join(dir, `zoom-${crypto.randomBytes(4).toString("hex")}.png`);
await runOk("sips", ["-s", "format", "png", "-c", String(Math.round(h)), String(Math.round(w)), "--cropOffset", String(Math.round(y)), String(Math.round(x)), src, "--out", out], { timeoutMs: 15_000 });
const parent = state.lastRaster;
state.lastRaster = { file: out, bytes: fs.statSync(out).size, source: src, region,
points: { x: (parent.points?.x ?? 0) + x / parent.scale, y: (parent.points?.y ?? 0) + y / parent.scale, w: w / parent.scale, h: h / parent.scale },
pixels: { w, h }, scale: parent.scale, capturedAt: new Date().toISOString() };
return state.lastRaster;
}
// ---------- recording ----------
const rec = new Map(); // Includes starting children so session close owns them too.
function requestRecordingStop(r) {View on GitHub (pinned to 73e0f67d83)