{"record":{"id":"06abf4c89ec55055","repo":"Hmbown/CodeWhale","slug":"zoom-failed-r-stderr-slice-0-250","errorCode":null,"errorMessage":"zoom failed: ${(r.stderr || \"\").slice(0, 250)}","messagePattern":"zoom failed: (.+?)","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/win32.mjs","lineNumber":441,"sourceCode":"      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() };\n      return { ...lastRaster };\n    },\n    zoom: async ({ source, region, path: outPath }) => {\n      const src = source ?? lastRaster?.file;\n      if (!src) throw new ExecError(\"no screenshot taken yet on this computer — call screenshot first\");\n      const out = outPath || path.join(recordingsDir(), `zoom-${crypto.randomBytes(4).toString(\"hex\")}.png`);\n      const script = `Add-Type -AssemblyName System.Drawing;\n$img = [System.Drawing.Image]::FromFile('${src.replace(/'/g, \"''\")}');\n$rect = New-Object System.Drawing.Rectangle(${Math.round(region[0])}, ${Math.round(region[1])}, ${Math.round(region[2])}, ${Math.round(region[3])});\n$bmp = New-Object System.Drawing.Bitmap($rect.Width, $rect.Height);\n$g = [System.Drawing.Graphics]::FromImage($bmp);\n$g.DrawImage($img, (New-Object System.Drawing.Rectangle(0, 0, $rect.Width, $rect.Height)), $rect, [System.Drawing.GraphicsUnit]::Pixel);\n$g.Dispose();\n$bmp.Save('${out.replace(/'/g, \"''\")}', [System.Drawing.Imaging.ImageFormat]::Png);\n$bmp.Dispose(); $img.Dispose();\nWrite-Output '{\"ok\": true}';`;\n      const r = await psOk(script, { timeoutMs: 20_000 });\n      if (r.code !== 0 || !fs.existsSync(out)) throw new ExecError(`zoom failed: ${(r.stderr || \"\").slice(0, 250)}`, r);\n      return { file: out, bytes: fs.statSync(out).size, region, source: src };\n    },\n    left_click: ({ target, strategy }) => { assertEventStrategy(strategy); return clickAt(0, target.x, target.y, 1); },\n    double_click: ({ target }) => clickAt(0, target.x, target.y, 2),\n    triple_click: ({ target }) => clickAt(0, target.x, target.y, 3),\n    right_click: ({ target }) => clickAt(1, target.x, target.y, 1),\n    middle_click: ({ target }) => clickAt(2, target.x, target.y, 1),\n    mouse_move: async ({ target }) => {\n      await withUser32(`[User32]::SetCursorPos(${Math.round(target.x)}, ${Math.round(target.y)}) | Out-Null; Write-Output '{\"ok\": true}'`);\n      return { action_sent: true, at: { x: target.x, y: target.y } };\n    },\n    left_click_drag: async ({ from_target: from, to }) => {\n      requireInputOwner();\n      throwIfAborted();\n      heldButtons.add(\"LEFT\");\n      try {\n      await withUser32(`[User32]::SetCursorPos(${Math.round(from.x)}, ${Math.round(from.y)}) | Out-Null;\nStart-Sleep -Milliseconds 80;","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/win32.mjs#L423-L459","documentation":"The win32 backend's zoom action runs a PowerShell script that captures a screen region with System.Drawing and saves a PNG. If the PowerShell process exits non-zero or the output file does not appear, the backend throws this ExecError with the first 250 characters of PowerShell's stderr attached. It signals that the native screenshot/zoom pipeline failed, not that the requested region was invalid.","triggerScenarios":"Calling zoom on the win32 backend when: the embedded PowerShell script throws (e.g. System.Drawing assembly fails to load, $rect has zero/negative dimensions), $bmp.Save fails (path locked, disk full, invalid output dir), the 20s timeout elapses, or fs.existsSync(out) is false after a nominally successful run.","commonSituations":"Windows sessions without a desktop (RDP disconnected, service context) where GDI screen capture returns empty; antivirus or policy blocking PowerShell; the temp output directory being cleaned mid-run; screen locked so the captured bitmap is invalid.","solutions":["Check the error's stderr/result payload (r is attached to the ExecError) for the actual PowerShell message and fix the underlying cause (display unavailable, path, permissions).","Ensure an interactive desktop session exists — reconnect RDP or run in a logged-in console session before retrying zoom.","Verify the output/recordings directory is writable and has free disk space.","Retry once; transient GDI failures during display changes often resolve on a second attempt.","Fall back to the plain screenshot action if zoom of a sub-region keeps failing."],"exampleFix":"// caller before\nconst shot = await backend.zoom({ region });\n// after\nlet shot;\ntry {\n  shot = await backend.zoom({ region });\n} catch (e) {\n  console.error('zoom stderr:', e.result?.stderr);\n  shot = await backend.screenshot({}); // fallback to full screen\n}","handlingStrategy":"try-catch","validationCode":"// ensure output dir writable and session has a desktop before zoom\nif (!fs.existsSync(recordingsDir())) throw new Error('output dir missing');","typeGuard":"const isZoomError = (e) => e instanceof Error && String(e.message).startsWith('zoom failed:');","tryCatchPattern":"try {\n  return await backend.zoom({ region });\n} catch (e) {\n  if (isZoomError(e)) return await backend.screenshot({}); // full-screen fallback\n  throw e;\n}","preventionTips":["Confirm an interactive desktop session (RDP connected, not locked) before screen capture calls.","Pre-check output directory writability and free disk space.","Inspect e.result.stderr on every zoom failure to learn the PowerShell-level cause.","Keep a screenshot fallback wired in for capture pipeline failures."],"tags":["windows","powershell","screenshot","gdi"],"backgroundTag":"api-error-response","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}