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
zoom crops/enlarges a region of a previously captured screenshot. The backend caches the last raster (lastRaster) per backend instance; if no screenshot has been taken yet and no explicit source path is given, it throws this ExecError telling the caller to call screenshot first.
Solutions
- Call screenshot() first, then zoom with the desired region
- Pass an explicit source path to an existing PNG if you want to zoom a specific image
- Handle the error by falling back to a fresh screenshot before retrying zoom
Example fix
// before
await zoom({ region: [0, 0, 200, 200] });
// after
await screenshot();
await zoom({ region: [0, 0, 200, 200] }); Defensive patterns
Strategy: fallback
Validate before calling
function ensureSource(backend, args = {}) {
if (args.source == null && !backend.lastRaster?.file) {
throw new Error("call screenshot() before zoom(), or pass an explicit source PNG path");
}
} Try / catch
try {
return await backend.zoom({ region });
} catch (e) {
if (String(e.message).includes("no screenshot taken yet")) {
await backend.screenshot();
return await backend.zoom({ region });
}
throw e;
} Prevention
- Always screenshot before zoom in the same backend session
- Remember zoom crops an existing PNG, not the live screen
- Pass an explicit source path when zooming arbitrary images
- Re-screenshot after backend restarts since lastRaster is in-memory
When it happens
Trigger: Calling zoom({region:[...]}) as the first action on a fresh backend instance; after a backend restart that cleared lastRaster; passing source: undefined/null explicitly; source pointing at logic path but never actually providing a path.
Common situations: Agents issuing zoom immediately after session start; assuming zoom reads the live screen (it only reads an existing PNG); previous screenshot call threw, so nothing was cached.
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
- screenshot did not return a valid raster
- screenshot failed
- Windows screenshot does not support app_ref or window_id…
- zoom failed
- zoom is not supported on the harmony backend yet —…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/52659d4ee5bcba8a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:428
const file = path.resolve(outPath || path.join(dir, `shot-${crypto.randomBytes(6).toString("hex")}.png`));
const meta = await psJson(`Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing;
$bounds = [System.Windows.Forms.SystemInformation]::VirtualScreen;
${display == null ? "" : `$screens = [System.Windows.Forms.Screen]::AllScreens; if (${display} -gt $screens.Count) { throw 'display index is out of range' }; $bounds = $screens[${display - 1}].Bounds;`}
${region == null ? "" : `$crop = New-Object System.Drawing.Rectangle(${region.join(",")}); if (-not $bounds.Contains($crop)) { throw 'region is outside capture bounds' }; $bounds = $crop;`}
$bmp = New-Object System.Drawing.Bitmap($bounds.Width, $bounds.Height);
try {
$g = [System.Drawing.Graphics]::FromImage($bmp);
try { $g.CopyFromScreen($bounds.X, $bounds.Y, 0, 0, $bounds.Size); } finally { $g.Dispose(); }
$bmp.Save('${file.replace(/'/g, "''")}', [System.Drawing.Imaging.ImageFormat]::Png);
} finally { $bmp.Dispose(); }
@{ x = $bounds.X; y = $bounds.Y; w = $bounds.Width; h = $bounds.Height } | ConvertTo-Json -Compress;`, { timeoutMs: 30_000 });
if (!fs.existsSync(file) || ![meta.x, meta.y, meta.w, meta.h].every(Number.isFinite) || meta.w <= 0 || meta.h <= 0) throw new ExecError("screenshot did not return a valid raster");
lastRaster = { file, bytes: fs.statSync(file).size, points: { x: meta.x, y: meta.y, w: meta.w, h: meta.h }, pixels: { w: meta.w, h: meta.h }, scale: 1, capturedAt: new Date().toISOString() };
return { ...lastRaster };
},
zoom: async ({ source, region, path: outPath }) => {
const src = source ?? lastRaster?.file;
if (!src) throw new ExecError("no screenshot taken yet on this computer — call screenshot first");
const out = outPath || path.join(recordingsDir(), `zoom-${crypto.randomBytes(4).toString("hex")}.png`);
const script = `Add-Type -AssemblyName System.Drawing;
$img = [System.Drawing.Image]::FromFile('${src.replace(/'/g, "''")}');
$rect = New-Object System.Drawing.Rectangle(${Math.round(region[0])}, ${Math.round(region[1])}, ${Math.round(region[2])}, ${Math.round(region[3])});
$bmp = New-Object System.Drawing.Bitmap($rect.Width, $rect.Height);
$g = [System.Drawing.Graphics]::FromImage($bmp);
$g.DrawImage($img, (New-Object System.Drawing.Rectangle(0, 0, $rect.Width, $rect.Height)), $rect, [System.Drawing.GraphicsUnit]::Pixel);
$g.Dispose();
$bmp.Save('${out.replace(/'/g, "''")}', [System.Drawing.Imaging.ImageFormat]::Png);
$bmp.Dispose(); $img.Dispose();
Write-Output '{"ok": true}';`;
const r = await psOk(script, { timeoutMs: 20_000 });
if (r.code !== 0 || !fs.existsSync(out)) throw new ExecError(`zoom failed: ${(r.stderr || "").slice(0, 250)}`, r);
return { file: out, bytes: fs.statSync(out).size, region, source: src };
},
left_click: ({ target, strategy }) => { assertEventStrategy(strategy); return clickAt(0, target.x, target.y, 1); },
double_click: ({ target }) => clickAt(0, target.x, target.y, 2),
triple_click: ({ target }) => clickAt(0, target.x, target.y, 3),View on GitHub (pinned to 73e0f67d83)