can1357/oh-my-pi · error · ToolError
Browser open timed out after ${timeoutMs}ms
Error message
Browser open timed out after ${timeoutMs}ms What it means
browser open wraps the entire open sequence (browser acquisition, tab queueing, worker startup, page navigation) under a requested timeout. If the timeout signal aborts before open completes — and the abort was not caller cancellation — this ToolError is thrown with the effective timeoutMs.
Source
Thrown at packages/coding-agent/src/tools/browser.ts:357
const tab = result.tab;
const url = tab.info.url;
const title = tab.info.title ?? "";
details.url = url;
details.viewport = tab.info.viewport;
const verb = result.created ? "Opened" : "Reused";
const lines = [
`${verb} tab ${JSON.stringify(name)} on ${describeBrowser(browser)}`,
`URL: ${url}`,
title ? `Title: ${title}` : null,
].filter((l): l is string => typeof l === "string");
details.result = lines.join("\n");
return toolResult(details).text(lines.join("\n")).done();
} catch (error) {
// Caller cancellation stays a ToolAbortError; the requested timeout
// becomes a timeout ToolError; anything else passes through unchanged.
if (signal?.aborted) throw error instanceof ToolAbortError ? error : new ToolAbortError();
if (timeoutSignal.aborted) throw new ToolError(`Browser open timed out after ${timeoutMs}ms`);
throw error;
}
}
async #close(
name: string,
params: BrowserParams,
details: BrowserToolDetails,
timeoutMs: number,
signal?: AbortSignal,
): Promise<AgentToolResult<BrowserToolDetails>> {
const kill = !!params.kill;
if (params.all) {
const count = await untilAborted(signal, () => releaseAllTabs({ kill, timeoutMs }));
details.result = `Released ${count} managed tab${count === 1 ? "" : "s"}`;
return toolResult(details).text(details.result).done();
}
const closed = await untilAborted(signal, () => releaseTab(name, { kill, timeoutMs }));View on GitHub (pinned to 9690622007)
Solutions
- Increase the open timeout parameter for cold starts or slow endpoints
- Verify the browser binary/CDP endpoint is reachable before opening (the hang is upstream of the timeout)
- Pre-warm the browser (open once early) so later opens are fast
- Open tabs sequentially or raise the timeout when opening many at once
Example fix
// before
await browser.run({ action: 'open', url, timeoutMs: 5000 })
// after
await browser.run({ action: 'open', url, timeoutMs: 30000 }) Defensive patterns
Strategy: retry
Validate before calling
// Sanity-check the endpoint before spending the open budget
const up = await fetch(cdpHttpUrl('/json/version'), { signal: AbortSignal.timeout(2000) }).then(r => r.ok).catch(() => false);
if (!up) throw new Error('browser endpoint unreachable'); Try / catch
try {
await browser.run({ action: 'open', url, timeoutMs });
} catch (err) {
if (err instanceof ToolError && /timed out/.test(err.message)) {
await Bun.sleep(1000);
await browser.run({ action: 'open', url, timeoutMs: timeoutMs * 2 }); // retry with backoff + larger budget
} else throw err;
} Prevention
- Set timeoutMs generously for cold starts (>= 30s)
- Pre-warm the browser early in the session
- Verify CDP endpoint/browser binary availability before opening
- Avoid opening many tabs concurrently on a tight timeout
When it happens
Trigger: Opening a tab when the browser must cold-start (slow machine, first launch); CDP discovery/connect hanging on an unreachable endpoint; very large page or slow navigation exceeding the timeout; timeoutMs set too low for the environment.
Common situations: Remote CDP endpoint behind a slow VPN; container without a browser binary causing retry loops until timeout; opening many tabs concurrently so the acquisition queue exceeds the budget; user set a small timeout default in config.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timed out waiting for CDP endpoint ${cdpUrl}${lastStatus !==
- tab.waitForUrl() timed out after ${timeoutMs}ms
- tab.waitForNavigation() timed out after ${timeoutMs}ms
- tab.waitForResponse() timed out after ${timeoutMs}ms
- page.waitForFunction() timed out after ${timeoutMs}ms
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1ae321a605f1c4f9.
Report an issue: GitHub.