BigPizzaV3/CodexPlusPlus · error · anyhow::Error
CDP WebSocket URL must include an explicit port
Error message
CDP WebSocket URL must include an explicit port
What it means
The port branch of validate_cdp_websocket_url (crates/codex-plus-core/src/cdp.rs:229) rejects ws/wss URLs without an explicit port. reqwest::Url knows default ports only for http/https/ftp, so port() is None for 'ws://127.0.0.1/devtools/...'. This validator is called from bridge.rs connect_cdp_websocket with the port it already parsed, so both sites fail together on the same input; this copy additionally enforces port == expected debug port afterwards.
Source
Thrown at crates/codex-plus-core/src/cdp.rs:229
pub fn validate_cdp_websocket_url(url: &str, expected_port: u16) -> anyhow::Result<()> {
let parsed = reqwest::Url::parse(url).context("invalid CDP WebSocket URL")?;
if !matches!(parsed.scheme(), "ws" | "wss") {
bail!("CDP WebSocket URL must use ws or wss");
}
let host = parsed
.host_str()
.ok_or_else(|| anyhow::anyhow!("CDP WebSocket URL has no host"))?;
let address = host
.trim_start_matches('[')
.trim_end_matches(']')
.parse::<IpAddr>()
.with_context(|| "CDP WebSocket host must be a loopback IP address")?;
if !address.is_loopback() {
bail!("CDP WebSocket host must be loopback");
}
let port = parsed
.port()
.ok_or_else(|| anyhow::anyhow!("CDP WebSocket URL must include an explicit port"))?;
if port != expected_port {
bail!("CDP WebSocket port {port} does not match debug port {expected_port}");
}
Ok(())
}
pub fn pick_page_target(targets: &[CdpTarget]) -> anyhow::Result<CdpTarget> {
let mut first_page = None;
for target in targets
.iter()
.filter(|target| is_injectable_page_target(target))
{
first_page.get_or_insert(target);
if is_primary_codex_page_target(target) {
return Ok(target.clone());
}
}
View on GitHub (pinned to 1f431ae49b)
Solutions
- Add the explicit port to the URL: ws://127.0.0.1:9222/devtools/browser/<id>
- Use webSocketDebuggerUrl from http://127.0.0.1:<port>/json/version verbatim — it always includes the port
- Validate user-supplied URLs early (scheme, host, port) and surface a clear message before the connect attempt
Example fix
# before ws://127.0.0.1/devtools/browser/4f8a... # after ws://127.0.0.1:9222/devtools/browser/4f8a...
Defensive patterns
Strategy: validation
Validate before calling
// One shared pre-flight for all CDP ws URLs
fn check_cdp_url(url: &str, expected_port: u16) -> anyhow::Result<()> {
let u = reqwest::Url::parse(url)?;
ensure!(matches!(u.scheme(), "ws" | "wss"), "need ws/wss");
ensure!(u.host_str().is_some(), "need host");
ensure!(u.port() == Some(expected_port), "need explicit port == {expected_port}");
validate_cdp_websocket_url(url, expected_port)
} Type guard
fn cdp_url_is_complete(url: &str, port: u16) -> bool {
reqwest::Url::parse(url).map(|u| {
matches!(u.scheme(), "ws" | "wss") && u.host_str().is_some() && u.port() == Some(port)
}).unwrap_or(false)
} Try / catch
if let Err(e) = validate_cdp_websocket_url(url, port) {
if e.to_string().contains("explicit port") {
// configuration defect: reject loudly at load time, not at connect time
return Err(e.context("CDP URL config is missing ':port' — fix settings"));
}
return Err(e);
} Prevention
- Reject port-less ws URLs at config-load time with a clear message
- Pin URLs to the known debug port when generating them
- Add unit tests asserting Url::port() is Some for every stored CDP URL
When it happens
Trigger: Calling validate_cdp_websocket_url() (directly or via bridge connection helpers) with a port-less ws URL such as ws://127.0.0.1/devtools/browser/<id>; the scheme and loopback-host checks have already passed when this fires.
Common situations: Stored/templated CDP URLs missing ':9222'; URL normalization that strips 'default-looking' ports; a custom debug port configuration where the URL was regenerated without the port field.
Related errors
- CDP WebSocket URL must include an explicit port
- CDP WebSocket URL has no host
- Page.captureScreenshot returned no image data
- browser WebSocket URL has no path
- selected CDP target has no websocket URL
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/690a9cb76806bed1.
Report an issue: GitHub.