Hmbown/CodeWhale · error · ExecError
powershell timed out after
Error message
powershell timed out after ${o.timeoutMs ?? 25_000}ms What it means
psOk wraps every PowerShell invocation and is 'truthful': unlike ps(), it throws instead of returning results on timeout, nonzero exit, or spawn failure. When the spawned powershell.exe exceeds the caller's timeoutMs (default 25s), it throws this ExecError with the effective timeout value.
Solutions
- Increase timeoutMs in the options object for slow operations (e.g. { timeoutMs: 60000 })
- Profile the script manually in powershell.exe to find the slow or blocking statement
- Trim UIA queries to smaller scopes (single window/element) instead of whole-desktop tree walks
- Retry once on timeout; also check for warm-up effects (first call after boot is much slower)
Example fix
// before
await psOk(uiaScript);
// after
await psOk(uiaScript, { timeoutMs: 60_000 }); Defensive patterns
Strategy: retry
Try / catch
let last;
for (const t of [25_000, 60_000]) {
try { return await psOk(script, { timeoutMs: t }); }
catch (e) { if (!/timed out/.test(e.message)) throw e; last = e; }
}
throw last; Prevention
- Budget generous timeouts for UIA-heavy scripts
- Warm up PowerShell once at session start to pay JIT/profile costs early
- Avoid modal dialogs that hang scripts mid-run
- Scope UIA queries narrowly to keep runtime predictable
When it happens
Trigger: Any computer-use operation backed by a PowerShell script (UIA queries, screenshots, window enumeration) exceeding its timeoutMs — e.g. slow UIA tree walks, hung COM automation, first-run .NET/PowerShell startup delays on cold machines, or an explicit small timeoutMs passed in options.
Common situations: 25s default too short for large UIA trees or AV-scanned PowerShell startup; a custom timeoutMs set optimistically low; a hung PowerShell child waiting on a modal dialog.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c9bf7792fe9bc43a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:182
if (opts.exec?.persistentInputOwner !== true) throw Object.assign(new ExecError(
"This held-input gesture requires a connected Codewhale Computer Use desktop helper so a disconnected client cannot leave keys or buttons pressed. Start the helper and reconnect before retrying."
), { code: "input_owner_required" });
}
async function ps(script, o = {}) {
throwIfAborted();
const encoded = Buffer.from(`$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';\n[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false);\n${script}`, "utf16le").toString("base64");
return runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded], {
timeoutMs: o.timeoutMs ?? 25_000,
maxBuffer: 32 * 1024 * 1024,
});
}
/** ps() but truthful: timeout, nonzero exit, and spawn failure all throw. */
async function psOk(script, o = {}) {
const r = await ps(script, o);
if (r.aborted) throw Object.assign(new ExecError("computer request cancelled", r), { code: "cancelled" });
if (r.timedOut) throw new ExecError(`powershell timed out after ${o.timeoutMs ?? 25_000}ms`, r);
if (r.code !== 0) {
const raw = (r.stderr || r.stdout).trim();
// EncodedCommand serializes errors as CLIXML; surface the error strings,
// not a truncated XML/progress header that conceals the actual failure.
const messages = [...raw.matchAll(/<S S="Error">([\s\S]*?)<\/S>/g)].map(m => m[1]
.replace(/_x([0-9A-Fa-f]{4})_/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&"));
throw new ExecError(`powershell.exe exited ${r.code}: ${(messages.join("") || raw).slice(0, 1600)}`, r);
}
return r;
}
async function psJson(script, o = {}) {
const r = await psOk(script, o);
const out = r.stdout.trim();
const j = tryJson(out, null);
if (!j) throw new ExecError(`powershell did not return JSON: ${(r.stderr || out).trim().slice(0, 300)}`, r);
return j;View on GitHub (pinned to 73e0f67d83)