fix: skip frozen/discarded targets in page enumeration#1841
fix: skip frozen/discarded targets in page enumeration#184120syldev wants to merge 2 commits intoChromeDevTools:mainfrom
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
8868f23 to
92aa2fc
Compare
OrKoN
left a comment
There was a problem hiding this comment.
Please add a test demonstrating that it works with actual frozen tabs in the browser and not only in the mock. As I mentioned on #1230 (comment) I have troubles reproducing the issue. Do you have additional details for the manual reproduction?
92aa2fc to
ae01916
Compare
How to reproduceThe issue requires a dead renderer — Steps:
This only happens with Added testThe new integration test (
$ NODE_TEST_REPORTER=spec npm test -- tests/McpContext.test.ts 2>&1 | grep -A2 "crashed renderer"✔ should enumerate pages when a tab has a crashed renderer (10459.212304ms)~10s = two |
Launches Chrome, crashes a tab via chrome://crash, disconnects and reconnects to verify page enumeration skips the dead target.
ae01916 to
2667068
Compare
| const type = target.type(); | ||
| if (type === 'page') return true; | ||
| if (this.#options.experimentalIncludeAllPages) { | ||
| return type === 'background_page' || type === 'webview'; |
There was a problem hiding this comment.
Is the enumeration here sufficient? type: What are the categories in total?
There was a problem hiding this comment.
The CDP target types are: page, background_page, service_worker, webview, worker, shared_worker, browser, and other.
Here only page is enumerated by default (same as what browser.pages() did before), and background_page + webview are added when experimentalIncludeAllPages is on — that's the pre-existing opt-in. The rest (service_worker, worker, etc.) aren't navigable pages so target.page() wouldn't return anything useful for them.
Problem
When Chrome freezes or discards background tabs (memory-saving behavior),
browser.pages()can time out onNetwork.enablefor those targets and abort the entire page enumeration — even though the rest of the browser and all active tabs are healthy.This causes any MCP tool that needs page enumeration (
list_pages,take_snapshot, navigation flows, etc.) to fail completely when the connected Chrome profile has been open long enough for background tabs to be frozen/discarded.Root cause
browser.pages()iterates every page-type target and callstarget.page()for each, which creates a Puppeteer CDP session and sends initialization commands includingNetwork.enable. Frozen/discarded targets cannot respond to page-session CDP commands, so they time out — and the error propagates out ofbrowser.pages(), killing the entire list.Fix
Replace the single
browser.pages()call in#getAllPages()with a per-target iteration overbrowser.targets(). Each call totarget.page()is wrapped in its owntry/catchso that one unresponsive background tab is logged and skipped instead of aborting the whole enumeration.pagetype targets are always included (existing behavior)background_page/webviewtypes are included whenexperimentalIncludeAllPagesis set (preserves existing opt-in behavior)allTargetssnapshot is reused for the extension-target loop below, so there is no extrabrowser.targets()callFixes #1230