can1357/oh-my-pi · info · ToolAbortError
Browser tab open aborted
Error message
Browser tab open aborted
What it means
acquireTabImpl checks the caller-supplied AbortSignal at dequeue time, before spawning a worker or holding a browser. If the signal is already aborted when the serialized open gets its turn, it throws a ToolAbortError instead of doing wasted work. This is intentional cooperative cancellation, not a fault in the library.
Source
Thrown at packages/coding-agent/src/tools/browser/tab-supervisor.ts:256
}
async function acquireTabImpl(
name: string,
browser: BrowserHandle,
opts: AcquireTabOptions,
): Promise<AcquireTabResult> {
// Worker-init deadline: the inline-fallback retry passes this same start
// so it can't restart the budget (which would let a cold import that
// consumed most of it spend the phase floors again for another full
// budget). Defaults to a fresh clock; callers whose own deadline started
// earlier (browser acquisition is not part of this budget) pass theirs
// through `deadlineStartMs` so that earlier time counts against it.
const startedAt = opts.deadlineStartMs ?? performance.now();
// Serialized opens can sit behind a slow predecessor in the per-name
// chain; honor an abort at dequeue instead of spawning a worker and
// browser hold nobody is waiting for.
if (opts.signal?.aborted) {
throw new ToolAbortError("Browser tab open aborted");
}
killedTabs.delete(name);
// Temporary refCount hold so releasing an existing tab on the SAME browser
// below cannot drop it to refCount 0 and dispose the instance we are about
// to reuse (e.g. reopening the sole tab with a different dialogs policy).
let tempHold = false;
const existing = tabs.get(name);
if (existing) {
if (existing.browser === browser && existing.state === "alive") {
const requestedCmuxSurface = "client" in browser ? (opts.cmuxSurface ?? browser.surface) : undefined;
if (existing.backend === "cmux" && existing.cmuxAttachedSurface !== requestedCmuxSurface) {
holdBrowser(browser);
tempHold = true;
await releaseTab(name, { kill: false });
} else if (opts.dialogs !== undefined && opts.dialogs !== existing.dialogPolicy) {
holdBrowser(browser);
tempHold = true;
await releaseTab(name, { kill: false });View on GitHub (pinned to 9690622007)
Solutions
- Treat as expected cancellation: catch ToolAbortError and return a cancelled result instead of retrying.
- If opens keep getting aborted while queued, reduce contention — avoid many concurrent opens of the same tab name.
- Re-issue the open with a fresh (non-aborted) signal if the operation should still happen.
- Check whether your own deadline/timeout is too aggressive relative to the open timeoutMs.
Example fix
// before
const tab = await acquireTab({ name: "docs", signal: alreadyAbortedSignal }); // throws
// after
if (signal.aborted) return cancelled();
const tab = await acquireTab({ name: "docs", signal }); Defensive patterns
Strategy: try-catch
Validate before calling
if (signal?.aborted) {
return cancelledResult(); // skip the call entirely
} Try / catch
try {
await acquireTab(opts);
} catch (e) {
if (e instanceof ToolAbortError && e.message === "Browser tab open aborted") {
return; // expected cancellation
}
throw e;
} Prevention
- Check signal.aborted before issuing opens
- Avoid long queues of serialized opens on the same tab name
- Pass an abort signal you actually control and cancel deliberately
When it happens
Trigger: The tool call's AbortSignal is aborted while the open request is queued behind a slow predecessor tab open with the same name; the caller cancels the action (user abort or deadline) before the worker starts.
Common situations: User presses escape / agent turn cancelled while a browser open is queued; a timeout deadline that elapsed during the wait; an outer tool runner aborting all in-flight operations.
Related errors
- Request was aborted
- Auth broker request aborted
- OAuth refresh ownership aborted by caller
- Request was aborted.
- AbortError
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/15464a5e28a2a028.
Report an issue: GitHub.