CDP Proxy fails to connect in WSL2: missing UUID in WebSocket path
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:
- The Linux paths (
~/.config/google-chrome/DevToolsActivePort) don't exist — Chrome runs on Windows - The
win32paths aren't checked becauseos.platform()returnslinuxin 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')})"
# → OKSuggested 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/versionendpoint 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-portbutDevToolsActivePortis missing or inaccessible - The
check-deps.mjsscript has the sameDevToolsActivePortpath limitation for WSL2, though it only affects port detection (not the connection failure)
Source: eze-is/web-access