Follow-up to #34561 / #34574, from review discussion there (Bugbot finding traced and confirmed by @AtofStryker).
Problem
When an auto-reconnecting CDPConnection exhausts its reconnection attempts (20 tries), it emits cdp-connection-reconnect-error but never sets _terminated, and CriClient never resets _connected. As of #34574, CriClient rejects the already-enqueued commands on that event — but any send() issued after exhaustion still sees a non-terminated connection, hits the disconnected-socket path, and re-enqueues into a queue that nothing will ever flush. Those promises never settle.
packages/server/lib/browsers/cdp-protocol/cdp-connection.ts (_reconnect, reconnect-exhausted branch) and packages/server/lib/browsers/cdp-protocol/cri-client.ts (send() terminated guards).
Scope / mitigation
Proposed fix
Treat reconnect exhaustion as terminal, making the two _rejectEnqueuedCommands triggers symmetric: set _terminated = true (and clean up the dead connection) when asyncRetry gives up in _reconnect, so the existing terminated guards in CriClient.send() reject subsequent sends instead of enqueuing them. Unit-cover the post-exhaustion send path.
Follow-up to #34561 / #34574, from review discussion there (Bugbot finding traced and confirmed by @AtofStryker).
Problem
When an auto-reconnecting
CDPConnectionexhausts its reconnection attempts (20 tries), it emitscdp-connection-reconnect-errorbut never sets_terminated, andCriClientnever resets_connected. As of #34574,CriClientrejects the already-enqueued commands on that event — but anysend()issued after exhaustion still sees a non-terminated connection, hits the disconnected-socket path, and re-enqueues into a queue that nothing will ever flush. Those promises never settle.packages/server/lib/browsers/cdp-protocol/cdp-connection.ts(_reconnect, reconnect-exhausted branch) andpackages/server/lib/browsers/cdp-protocol/cri-client.ts(send()terminated guards).Scope / mitigation
terminatedcheck, so these sends parked forever before that change too.CDP_COULD_NOT_RECONNECTwithisFatalApiErr = true, which tears the run down.Proposed fix
Treat reconnect exhaustion as terminal, making the two
_rejectEnqueuedCommandstriggers symmetric: set_terminated = true(and clean up the dead connection) whenasyncRetrygives up in_reconnect, so the existing terminated guards inCriClient.send()reject subsequent sends instead of enqueuing them. Unit-cover the post-exhaustion send path.