Hmbown/CodeWhale · error · ExecError
screenshot failed
Error message
screenshot failed: ${(r.stderr || r.stdout).trim().slice(0, 300)} What it means
The win32 screenshot action runs a System.Drawing CopyFromScreen script via ps() with a 30s timeout, then requires both a zero exit code and that the expected PNG file exists on disk. Either condition failing throws this ExecError with up to 300 chars of stderr/stdout explaining the capture failure.
Solutions
- Read the stderr/stdout excerpt in the message for the actual capture error
- Ensure the process runs in an interactive desktop session (not a service/SSH headless session)
- Verify System.Drawing/GDI+ works on the host and recordingsDir() is writable with free disk space
- Retry once — transient session/disconnect states (RDP detach) break CopyFromScreen
Defensive patterns
Strategy: try-catch
Try / catch
try {
const shot = await computer.screenshot();
} catch (e) {
if (/screenshot failed/.test(e.message)) {
// check session has an interactive desktop; retry once after a short delay
}
} Prevention
- Ensure the automation runs inside an interactive desktop session (no Session 0/SSH headless)
- Verify recordingsDir() is writable and has free disk space
- Confirm System.Drawing/GDI+ is functional on the host before batch runs
When it happens
Trigger: screenshot() where the PowerShell capture script exits nonzero (Add-Type/GDI failure, session without a desktop) or exits 0 but the output PNG file was never written to recordingsDir().
Common situations: Running in a session without an interactive desktop (Session 0 service, SSH without console); GDI+ / System.Drawing broken on the host; antivirus blocking the PNG write; disk full so bmp.Save fails; multi-monitor coordinate issues producing a zero-size capture.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- screenshot did not return a valid raster
- zoom failed
- no screenshot taken yet on this computer — call screenshot…
- Windows screenshot does not support app_ref or window_id…
- application window not found in UIA tree — pass…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/6020529daf2a6bcd.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:348
},
screenshot: async (args = {}) => {
if (Object.hasOwn(args, "app_ref") || Object.hasOwn(args, "window_id")) throw unsupportedSelector("Windows screenshot does not support app_ref or window_id; omit them for a desktop screenshot");
const { display, region, path: outPath } = args;
const dir = recordingsDir();
fs.mkdirSync(dir, { recursive: true });
const file = outPath || path.join(dir, `shot-${new Date().toISOString().replace(/[:.]/g, "-")}-${crypto.randomBytes(3).toString("hex")}.png`);
const winPath = file.replace(/\\/g, "\\\\");
const script = `Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing;
$bounds = [System.Windows.Forms.SystemInformation]::VirtualScreen;
$bmp = New-Object System.Drawing.Bitmap($bounds.Width, $bounds.Height);
$g = [System.Drawing.Graphics]::FromImage($bmp);
$g.CopyFromScreen($bounds.X, $bounds.Y, 0, 0, $bounds.Size);
$g.Dispose();
$bmp.Save('${file.replace(/'/g, "''")}', [System.Drawing.Imaging.ImageFormat]::Png);
$bmp.Dispose();
Write-Output '{"ok": true, "w": ' + $bounds.Width + ', "h": ' + $bounds.Height + '}';`;
const r = await ps(script, { timeoutMs: 30_000 });
if (r.code !== 0 || !fs.existsSync(file)) throw new ExecError(`screenshot failed: ${(r.stderr || r.stdout).trim().slice(0, 300)}`, r);
const meta = tryJson(r.stdout.trim().split("\n").pop(), {});
lastRaster = { file, bytes: fs.statSync(file).size, points: { x: 0, y: 0, 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}';`;View on GitHub (pinned to 433685b202)