openclaw - ✅(Solved) Fix Browser: Remote CDP WebSocket needs auto-reconnect [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#67728Fetched 2026-04-17 08:29:32
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
commented ×1cross-referenced ×1referenced ×1

Root Cause

The CDP connection logic in cdp.helpers uses withCdpSocket:

async function withCdpSocket(wsUrl, fn, opts) {
  const ws = openCdpWebSocket(wsUrl, opts);
  const send = createCdpSender(ws);
  try {
    await openPromise; // single open attempt
    return await fn(send);
  } catch (err) {
    closeWithError(err);
    throw err; // NO RETRY, NO RECONNECT
  }
}

Key issues:

  1. No reconnection on close: ws.once("close", () => reject(...)) — connection drop = hard fail
  2. No retry with backoff: transient network failures kill the session immediately
  3. No connection keep-alive: every action reconnects from scratch
  4. Remote CDP especially vulnerable: cross-host setups (WSL2→Windows, Docker→remote Chrome) have higher packet loss

Fix Action

Fixed

PR fix notes

PR #67748: Add resilient auto-reconnect with jittered exponential backoff for re…

Description (problem / solution / changelog)

This change hardens the browser CDP transport by adding retry-based reconnection logic to withCdpSocket in cdp.helpers. Previously, a transient socket close (common in cross-host setups like WSL2 -> Windows Chrome) caused a hard failure and left subsequent browser actions failing with CDP socket closed until the gateway was restarted.

Key improvements:

Retry CDP WebSocket connection attempts on transient transport failures. Use jittered exponential backoff to avoid immediate reconnect storms. Keep existing behavior for non-retryable/rate-limit style failures. Add coverage for both recovery and retry-exhausted failure scenarios. Impact:

Remote CDP packet loss can now recover automatically. Temporary Chrome/CDP restarts are more likely to self-heal. Cross-host remote CDP usage is significantly more reliable. Closes: #67728

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem:
  • Why it matters:
  • What changed:
  • What did NOT change (scope boundary):

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause:
  • Missing detection / guardrail:
  • Contributing context (if known):

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
  • Scenario the test should lock in:
  • Why this is the smallest reliable guardrail:
  • Existing test that already covers this (if any):
  • If no new test is added, why not:

User-visible / Behavior Changes

List user-visible changes (including defaults/config).
If none, write None.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

Before:
[user action] -> [old state]

After:
[user action] -> [new state] -> [result]

Security Impact (required)

  • New permissions/capabilities? (Yes/No)
  • Secrets/tokens handling changed? (Yes/No)
  • New/changed network calls? (Yes/No)
  • Command/tool execution surface changed? (Yes/No)
  • Data access scope changed? (Yes/No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS:
  • Runtime/container:
  • Model/provider:
  • Integration/channel (if any):
  • Relevant config (redacted):

Steps

Expected

Actual

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
  • Edge cases checked:
  • What you did not verify:

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No)
  • Config/env changes? (Yes/No)
  • Migration needed? (Yes/No)
  • If yes, exact upgrade steps:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk:
    • Mitigation:

Changed files

  • extensions/browser/src/browser/cdp.helpers.ts (modified, +91/-23)
  • extensions/browser/src/browser/cdp.test.ts (modified, +62/-1)

Code Example

async function withCdpSocket(wsUrl, fn, opts) {
  const ws = openCdpWebSocket(wsUrl, opts);
  const send = createCdpSender(ws);
  try {
    await openPromise; // single open attempt
    return await fn(send);
  } catch (err) {
    closeWithError(err);
    throw err; // NO RETRY, NO RECONNECT
  }
}
RAW_BUFFERClick to expand / collapse

Problem

When using OpenClaw's browser tool with remote CDP (e.g., Chrome on Windows from WSL2), the CDP WebSocket connection is "one-shot": each browser action opens a new WebSocket, sends one command, and closes. If the connection drops mid-session, every subsequent action fails with "CDP socket closed" until the gateway is restarted.

Root Cause

The CDP connection logic in cdp.helpers uses withCdpSocket:

async function withCdpSocket(wsUrl, fn, opts) {
  const ws = openCdpWebSocket(wsUrl, opts);
  const send = createCdpSender(ws);
  try {
    await openPromise; // single open attempt
    return await fn(send);
  } catch (err) {
    closeWithError(err);
    throw err; // NO RETRY, NO RECONNECT
  }
}

Key issues:

  1. No reconnection on close: ws.once("close", () => reject(...)) — connection drop = hard fail
  2. No retry with backoff: transient network failures kill the session immediately
  3. No connection keep-alive: every action reconnects from scratch
  4. Remote CDP especially vulnerable: cross-host setups (WSL2→Windows, Docker→remote Chrome) have higher packet loss

Proposed Solutions

Option A: Built-in Reconnection in cdp.helpers

Modify withCdpSocket to retry with jittered exponential backoff on connection failure.

Option B: CDP Proxy Plugin

Provide a cdp-proxy plugin that maintains persistent WebSocket to Chrome with auto-reconnect.

Option C: Configurable Retry Flags

Add remoteCdpMaxRetries, remoteCdpRetryDelayMs, remoteCdpKeepAlive to browser profile config.

Impact

ScenarioCurrentWith Reconnect
Remote CDP packet lossFull session deathAuto-recover
Chrome temporary restartGateway restart requiredTransparent
Cross-host WSL2→WindowsVery unreliableReliable

References

  • EvoMap Capsule: "WebSocket Reconnection with Jittered Exponential Backoff" (GDI: 71.2, Streak: 83)
  • Related POC: server.silent-scope-upgrade-reconnect.poc.test.ts

extent analysis

TL;DR

Implementing a reconnection mechanism with jittered exponential backoff in the withCdpSocket function is likely to fix the "one-shot" CDP WebSocket connection issue.

Guidance

  • Modify the withCdpSocket function to retry with backoff on connection failure, as proposed in Option A, to handle transient network failures and connection drops.
  • Consider adding a keep-alive mechanism to maintain the WebSocket connection between actions, reducing the need for frequent reconnections.
  • Evaluate the feasibility of implementing a cdp-proxy plugin, as outlined in Option B, to provide a persistent WebSocket connection with auto-reconnect capabilities.
  • Review the proposed configurable retry flags in Option C to determine if they can be used to fine-tune the reconnection behavior for remote CDP scenarios.

Example

async function withCdpSocket(wsUrl, fn, opts) {
  const ws = openCdpWebSocket(wsUrl, opts);
  const send = createCdpSender(ws);
  const maxRetries = 5;
  const retryDelayMs = 500;
  let retries = 0;

  async function attempt() {
    try {
      await openPromise;
      return await fn(send);
    } catch (err) {
      if (retries < maxRetries) {
        retries++;
        await new Promise(resolve => setTimeout(resolve, retryDelayMs * (2 ** retries)));
        return attempt();
      } else {
        closeWithError(err);
        throw err;
      }
    }
  }

  return attempt();
}

Notes

The proposed solutions aim to address the "one-shot" connection issue, but the best approach may depend on the specific requirements and constraints of the project. It is essential to evaluate the trade-offs between the different options and consider factors such as performance, reliability, and maintainability.

Recommendation

Apply workaround by implementing a reconnection mechanism with jittered exponential backoff, as it directly addresses the root cause of the issue and can be implemented within the existing cdp.helpers codebase.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING