{"record":{"id":"15464a5e28a2a028","repo":"can1357/oh-my-pi","slug":"browser-tab-open-aborted","errorCode":null,"errorMessage":"Browser tab open aborted","messagePattern":"Browser tab open aborted","errorType":"exception","errorClass":"ToolAbortError","httpStatus":null,"severity":"info","filePath":"packages/coding-agent/src/tools/browser/tab-supervisor.ts","lineNumber":256,"sourceCode":"}\n\nasync function acquireTabImpl(\n\tname: string,\n\tbrowser: BrowserHandle,\n\topts: AcquireTabOptions,\n): Promise<AcquireTabResult> {\n\t// Worker-init deadline: the inline-fallback retry passes this same start\n\t// so it can't restart the budget (which would let a cold import that\n\t// consumed most of it spend the phase floors again for another full\n\t// budget). Defaults to a fresh clock; callers whose own deadline started\n\t// earlier (browser acquisition is not part of this budget) pass theirs\n\t// through `deadlineStartMs` so that earlier time counts against it.\n\tconst startedAt = opts.deadlineStartMs ?? performance.now();\n\t// Serialized opens can sit behind a slow predecessor in the per-name\n\t// chain; honor an abort at dequeue instead of spawning a worker and\n\t// browser hold nobody is waiting for.\n\tif (opts.signal?.aborted) {\n\t\tthrow new ToolAbortError(\"Browser tab open aborted\");\n\t}\n\tkilledTabs.delete(name);\n\t// Temporary refCount hold so releasing an existing tab on the SAME browser\n\t// below cannot drop it to refCount 0 and dispose the instance we are about\n\t// to reuse (e.g. reopening the sole tab with a different dialogs policy).\n\tlet tempHold = false;\n\tconst existing = tabs.get(name);\n\tif (existing) {\n\t\tif (existing.browser === browser && existing.state === \"alive\") {\n\t\t\tconst requestedCmuxSurface = \"client\" in browser ? (opts.cmuxSurface ?? browser.surface) : undefined;\n\t\t\tif (existing.backend === \"cmux\" && existing.cmuxAttachedSurface !== requestedCmuxSurface) {\n\t\t\t\tholdBrowser(browser);\n\t\t\t\ttempHold = true;\n\t\t\t\tawait releaseTab(name, { kill: false });\n\t\t\t} else if (opts.dialogs !== undefined && opts.dialogs !== existing.dialogPolicy) {\n\t\t\t\tholdBrowser(browser);\n\t\t\t\ttempHold = true;\n\t\t\t\tawait releaseTab(name, { kill: false });","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/tab-supervisor.ts#L238-L274","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst tab = await acquireTab({ name: \"docs\", signal: alreadyAbortedSignal }); // throws\n// after\nif (signal.aborted) return cancelled();\nconst tab = await acquireTab({ name: \"docs\", signal });","handlingStrategy":"try-catch","validationCode":"if (signal?.aborted) {\n  return cancelledResult(); // skip the call entirely\n}","typeGuard":null,"tryCatchPattern":"try {\n  await acquireTab(opts);\n} catch (e) {\n  if (e instanceof ToolAbortError && e.message === \"Browser tab open aborted\") {\n    return; // expected cancellation\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["abort","cancellation","browser"],"backgroundTag":"operation-aborted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}