Files
Victor Hugo Macedo Paes Leme 172656ab38 fix(console): stop resolving a cyclic Error.cause chain after 10 causes (#3338)
Fixes #3337

`SymbolizedError` follows `Error.cause` recursively with no limit. With
a cyclic chain like `e.cause = e` it never stops, because CDP returns a
new object id for the same object on every lookup. `get_console_message`
hangs and keeps the page queue busy, so other tools (even `list_pages`)
are stuck until the server restarts.

This stops the lookup after 10 causes. The recursion now goes through
private `#fromDetails()` / `#fromError()` that carry the depth, and the
public `fromDetails()` / `fromError()` signatures stay the same.
Detecting the cycle by object id doesn't work here since the ids are
different every time.

What changes for users: `get_console_message` for `Error` arguments, and
`get_console_message` / `list_console_messages` with
`includeStackTraces` for uncaught errors, show at most 10 `Caused by:`
entries. Chains with up to 10 causes look the same as before.

Testing:

- Added a test where a mocked session keeps returning the same error
with a new object id. It fails on main (`actual: 50, expected: 10`, the
mock cuts the chain at 50 so the test fails instead of hanging) and
passes with the fix.
- `npm run test` passes locally (Linux, Node 24, Chrome 156).
- Ran the repro from the issue: `get_console_message` comes back right
away and `take_snapshot` / `list_pages` keep working.

Side note: `DebuggerWorkspaceBinding.createSymbolizedError()` in
devtools-frontend recurses on `RemoteError.cause()` the same way, but
chrome-devtools-mcp doesn't use it, so this fix doesn't depend on an
upstream change.
2026-10-26 14:18:11 +00:00
..