BigPizzaV3/CodexPlusPlus · error · anyhow::Error

CDP websocket closed before response for

Error message

CDP websocket closed before response for {method} id {message_id}

What it means

wait_for_id pumps incoming CDP messages until a response whose id matches the pending command arrives. If next_message() returns None — the websocket stream ended — any still-pending command can never be answered, so the session bails with "CDP websocket closed before response for {method} id {message_id}". It reports the method and message id of the abandoned command.

Solutions

  1. Reconnect to the CDP websocket (connect_cdp_websocket) and re-issue the command in a fresh session
  2. Check the target is still alive (correct websocket_url, tab not closed/crashed) before sending
  3. Wrap CDP session usage in retry-once logic that re-establishes the connection on this error
  4. For long operations, keep the target page open and avoid navigation that invalidates the session

Example fix

// before
let resp = session.send_command(id, method, params).await?;
// after
let resp = match session.send_command(id, method, params).await {
    Ok(r) => r,
    Err(e) if e.to_string().contains("websocket closed") => {
        session = reconnect(websocket_url).await?;
        session.send_command(id, method, params).await?
    }
};
Defensive patterns

Strategy: retry

Validate before calling

// confirm the CDP endpoint is alive before sending
let ws_ok = tokio_tungstenite::connect_async(&websocket_url).await.is_ok();
if !ws_ok { eprintln!("CDP endpoint unreachable"); }

Try / catch

match session.send_command(id, method, params).await {
    Ok(r) => r,
    Err(e) if e.to_string().contains("websocket closed before response") => {
        session = CdpSession::new(connect_cdp_websocket(&websocket_url).await?);
        session.send_command(id, method, params).await?
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: The browser/tab closed, the debug port dropped the connection, or the page navigated in a way that tore down the CDP session while send_command was awaiting its response.

Common situations: Target tab was closed or crashed during a long-running command; DevTools remote debugging port dropped; the app under automation exited; network interruption to the CDP endpoint; awaiting a command the target never answers and the socket then closes.

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 BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/3b0ef79564b789ce. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/bridge.rs:716

                    "method": method,
                    "params": params,
                })
                .to_string()
                .into(),
            ))
            .await
            .with_context(|| format!("failed to send CDP command {method} id {message_id}"))?;
        Ok(())
    }

    async fn wait_for_id(&mut self, message_id: u64, method: String) -> anyhow::Result<Value> {
        loop {
            if let Some(response) = self.responses.remove(&message_id) {
                return command_result(response, &method, message_id);
            }

            let Some(message) = self.next_message().await? else {
                bail!("CDP websocket closed before response for {method} id {message_id}");
            };

            if let Some(response_id) = message.get("id").and_then(Value::as_u64) {
                if response_id == message_id {
                    return command_result(message, &method, message_id);
                }
                self.responses.insert(response_id, message);
            }
        }
    }

    async fn next_message(&mut self) -> anyhow::Result<Option<Value>> {
        let Some(message) = self.socket.next().await else {
            return Ok(None);
        };
        let message = message.context("failed to read CDP websocket message")?;
        let Message::Text(text) = message else {
            return Ok(Some(json!({})));

View on GitHub (pinned to b1ed92e5e4)