Skip to content

CDP Proxy fails to connect in WSL2: missing UUID in WebSocket path #53

Description

@pine2D

Environment

  • OS: WSL2 (Ubuntu) connecting to Chrome on Windows host
  • Chrome: 146.0.7680.178 (Windows)
  • Node.js: v24.14.1
  • web-access: 2.4.2
  • Chrome launch: --remote-debugging-port=9222 --user-data-dir=D:\ChromeDebugProfile

Problem

CDP Proxy repeatedly fails with 连接错误: 连接失败 when running in WSL2.

Root cause: In WSL2, discoverChromePort() in cdp-proxy.mjs cannot find the DevToolsActivePort file because:

  1. The Linux paths (~/.config/google-chrome/DevToolsActivePort) don't exist — Chrome runs on Windows
  2. The win32 paths aren't checked because os.platform() returns linux in WSL

So it falls through to port scanning, which finds port 9222 but returns { port, wsPath: null }. Then getWebSocketUrl() builds ws://127.0.0.1:9222/devtools/browser without a UUID.

Modern Chrome (tested on 146) rejects WebSocket connections without the browser UUID in the path — resulting in a 1006 close code.

Reproduction

# In WSL2, with Chrome remote debugging on Windows:

# This fails (no UUID):
node -e "const ws = new WebSocket('ws://127.0.0.1:9222/devtools/browser'); ws.onerror = e => console.log('FAIL', e.type); ws.onclose = e => console.log('code', e.code)"
# → FAIL error, code 1006

# This works (with UUID):
node -e "fetch('http://127.0.0.1:9222/json/version').then(r=>r.json()).then(j=>{const ws = new WebSocket(j.webSocketDebuggerUrl); ws.onopen = () => console.log('OK')})"
# → OK

Suggested Fix

After port scanning succeeds, fetch the UUID via HTTP API before returning:

// In discoverChromePort(), the port scanning fallback section:
for (const port of commonPorts) {
    const ok = await checkPort(port);
    if (ok) {
      console.log(`[CDP Proxy] 扫描发现 Chrome 调试端口: ${port}`);
      // Fetch UUID-bearing wsPath from HTTP API (required by modern Chrome)
      let wsPath = null;
      try {
        const resp = await fetch(`http://127.0.0.1:${port}/json/version`);
        const info = await resp.json();
        if (info.webSocketDebuggerUrl) {
          const url = new URL(info.webSocketDebuggerUrl);
          wsPath = url.pathname;
        }
      } catch (e) { /* fall through with null wsPath */ }
      return { port, wsPath };
    }
}

This is a minimal, non-breaking change — it only adds a /json/version HTTP call (not a WebSocket, so it won't trigger Chrome's authorization popup) as a fallback when DevToolsActivePort is unavailable.

Notes

  • The /json/version endpoint is a standard Chrome DevTools Protocol HTTP API, available whenever remote debugging is active
  • This fix also benefits any Linux environment where Chrome is started with --remote-debugging-port but DevToolsActivePort is missing or inaccessible
  • The check-deps.mjs script has the same DevToolsActivePort path limitation for WSL2, though it only affects port detection (not the connection failure)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions