Kuberwastaken/claurst · error

WebSocket connect to

Error message

WebSocket connect to {} failed: {}

What it means

Thrown by `connect` when the tungstenite `connect_async` call to Chrome's webSocketDebuggerUrl fails. The HTTP target lookup succeeded, but establishing the CDP WebSocket handshake did not; the underlying tungstenite error is embedded in the message.

Solutions

  1. Confirm Chrome is still running and the debug port is alive (`curl http://127.0.0.1:<port>/json/version`).
  2. Re-run `/chrome connect` — the previous ws URL may be stale after a Chrome restart.
  3. Check firewall/proxy settings that could block the WebSocket upgrade on the debug port.
  4. Retry with a fresh port if Chrome was relaunched with a different --remote-debugging-port.

Example fix

// before: stale URL after Chrome restart
let (ws, _) = connect_async(&ws_url).await?;

// after: re-fetch target list immediately before dialing
let targets = fetch_targets(port).await?;
let ws_url = pick_page_ws_url(&targets)?;
let (ws, _) = connect_async(&ws_url).await.map_err(|e| anyhow!("WebSocket connect to {} failed: {}", ws_url, e))?;
Defensive patterns

Strategy: retry

Validate before calling

let alive = reqwest::get(format!("http://127.0.0.1:{}/json/version", port)).await.is_ok();
if !alive { /* Chrome is down; restart it before connecting */ }

Type guard

async fn ws_reachable(ws_url: &str) -> bool {
    // cheap check: HTTP endpoint on the same port still answers
    ws_url.parse::<reqwest::Url>().is_ok() && port_probe(ws_url).await
}

Try / catch

match connect(port).await {
    Ok(s) => Ok(s),
    Err(e) if e.to_string().contains("WebSocket connect") => {
        tokio::time::sleep(Duration::from_millis(500)).await;
        connect(port).await // retry once with fresh target list
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Chrome closed between the /json HTTP query and the WebSocket dial; the ws URL host/port unreachable; proxy or TLS interference; Chrome restarted and the tab (and its debugger URL) is gone; the ws_url from a stale target list no longer accepts connections.

Common situations: Race where Chrome is shutting down while connect runs; connecting to a Docker-mapped port where only the HTTP endpoint is forwarded; wrong port collision (another service answering /json-shaped responses).

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/b41e4724692e00af. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/commands/src/chrome.rs:146

            .ok_or_else(|| {
                anyhow::anyhow!(
                    "No debuggable page found on port {}. \
                     Make sure Chrome has at least one open tab.",
                    port
                )
            })?;

        let tab_url = tabs
            .as_array()
            .and_then(|arr| {
                arr.iter()
                    .find(|t| t["type"] == "page")
                    .and_then(|t| t["url"].as_str().map(|s| s.to_string()))
            })
            .unwrap_or_default();

        let (ws, _) = connect_async(&ws_url).await.map_err(|e| {
            anyhow::anyhow!("WebSocket connect to {} failed: {}", ws_url, e)
        })?;

        let mut session = ChromeSession { ws, port, tab_url: tab_url.clone() };
        // Enable Page domain so captureScreenshot etc. work.
        cdp_call(&mut session.ws, "Page.enable", json!({})).await?;
        // Enable Runtime domain for eval/click/fill.
        cdp_call(&mut session.ws, "Runtime.enable", json!({})).await?;

        store_session(session);

        Ok(format!(
            "Connected to Chrome on port {} (tab: {})",
            port, tab_url
        ))
    }

    /// Disconnect the current session.
    pub fn disconnect() -> String {

View on GitHub (pinned to b0637c97ec)