Note
Grok responding on behalf of Julius.
Triage
Confirmed on main (0678e4e23d86): one timed-out call on the server's own browser evicts the whole server-browser host, which fails every other in-flight preview call in the environment, including an unrelated preview_open. The first snapshot stall itself is not explained here. It looks like #16567.
What the code does
- A timeout on any call evicts the shared host. When a call gets no answer before its deadline, the broker calls
disconnect(..., true)(PreviewAutomationBroker.ts#L654-L665). Only the background metadata read is exempt.removeConnectionFromStatedrops every pending request and every session's host assignment on that connection (#L140-L162), andcloseConnectionfails each pending request withPreviewAutomationClientDisconnectedError(#L359-L379). That error's message is "Preview automation client server-browser disconnected during open." (previewAutomation.ts#L1060). - The host is one connection shared by the whole environment. The server browser registers once, with a fixed
clientIdandpreferred: true(ServerBrowser.ts#L2150-L2181), and preferred hosts are picked first (PreviewAutomationBroker.ts#L548-L556). So one tab's 15s snapshot timeout fails other tabs' and other threads' requests that are still in flight. That includes anopenon this host, whose 660s budget for a first-time Chromium install (#L562-L565) doesn't protect it from someone else's 15s deadline. Until the host loop registers again afterHOST_RECONNECT_DELAY(1s, ServerBrowser.ts#L88), new calls getPreviewAutomationNoAvailableHostError, whose message says "Do not retry" (previewAutomation.ts#L898). - Eviction doesn't stop the server-side work.
handleRequestwrapsrunOperationinEffect.tryPromisewith no abort signal and runs in a forked fiber (ServerBrowser.ts#L1706-L1731, #L2162-L2170). Its later reply is thrown away because the request is no longer pending under that connection (PreviewAutomationBroker.ts#L480-L493). For an evictedopen, the tab can still be created on the server after the caller has already been told the call failed. - A stalled snapshot keeps holding its tab. Snapshot and evaluate run in the tab's
SessionControlqueue (ServerBrowser.ts#L1605-L1617), and that queue has no per-action timeout (SessionControl.ts#L37-L44).evaluatesendsRuntime.evaluatewithout a timeout (ServerBrowserPage.ts#L413-L418). A later evaluate on the same tab waits behind the stuck snapshot, which fits the 17:37:18 evaluate timeout that followed the fresh tab's snapshot timeout.
The reporter's two hypotheses
includeImage: falsestill takes a screenshot: confirmed. The MCP handler removesincludeImageandsavebefore forwarding (handlers.ts#L211-L215).ServerBrowserPage.snapshotalways runspage.evaluate,ariaSnapshotandcaptureViewporttogether (ServerBrowserPage.ts#L191-L200), andcaptureViewportsends a barePage.captureScreenshot(#L170-L174).- Equal deadlines: confirmed, but there's no real race.
ariaSnapshotusesDEFAULT_TIMEOUT_MS = 15_000(ServerBrowserPage.ts#L66), andsnapshotgets the broker default of 15000ms. The broker's clock starts first, before the request is handed off and before any wait in the tab queue. So the broker always fires first, andariaSnapshot's own timeout can never get back to the caller. Thepage.evaluateand screenshot branches have no timeout at all.
Not confirmed
- Why the first snapshot on
example.comstalled on Windows. #16567 shows a desktop-rendered background tab whosePage.captureScreenshotnever settles. The report doesn't say whether the stalled tab was desktop-rendered or headless (the later working tab was headless), so this may or may not be the same trigger.
Fix direction
- Don't evict the in-process
server-browserhost when a call times out. It isn't unreachable, so fail only the call that timed out and leave the connection, the other pending requests and the session assignments alone. - Bound each snapshot stage (especially
Page.captureScreenshot) andRuntime.evaluatebelow the broker deadline, and release the tab'sSessionControlslot when the broker gives up. This overlaps with #16567. - Optionally, skip the screenshot when
includeImage: false.
Related
- #16567 (open): the same unbounded snapshot and stuck tab queue, on macOS background tabs. Fixing it would remove this trigger but wouldn't stop a timeout from evicting the host.
- #16264, #16764, #12898, #12273, #12319, #16779 (open): other timeouts that evict the host, mostly on the desktop host. This report adds the in-process server host and the in-flight
openfailure. - #15965 and #14084 (open PRs) only change the desktop web host (
apps/web). The server browser consumes requests directly throughStream.runForEach, so neither covers this. #16620 (open PR) changes which engine renders a server tab, not the eviction or snapshot bounds. #12899 and #12279 exempt onlywaitFormisses and metadata reads. - The Cloudflare challenge failures are out of scope here and are tracked in #16596 (with #5002 closed).