zed-industries/zed · error
Cannot have two different ports in debug configuration
Error message
Cannot have two different ports in debug configuration
What it means
debugpy attach validation, port variant: on an attach request, if `tcp_connection.port` is already set and the adapter `config` object also carries a `"port"` key, Zed refuses to choose between two different port sources and bails (python.rs:379). It prevents connecting to the wrong debugpy listener.
Source
Thrown at crates/dap_adapters/src/python.rs:379
.unwrap_or_else(|| {
(
config
.config
.get("port")
.and_then(|port| port.as_u64().map(|p| p as u16)),
config.config.get("host").and_then(|host| host.as_str()),
)
});
let is_attach_with_connect = if config
.config
.get("request")
.is_some_and(|val| val.as_str().is_some_and(|request| request == "attach"))
{
if tcp_connection.host.is_some() && config_host.is_some() {
bail!("Cannot have two different hosts in debug configuration")
} else if tcp_connection.port.is_some() && config_port.is_some() {
bail!("Cannot have two different ports in debug configuration")
}
if let Some(hostname) = config_host {
tcp_connection.host = Some(hostname.parse().context("invalid IP address")?);
}
tcp_connection.port = config_port;
DebugpyLaunchMode::AttachWithConnect { host: config_host }
} else {
DebugpyLaunchMode::Normal
};
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
let python_path = if let Some(toolchain) = python_from_toolchain {
Some(toolchain)
} else {
Self::system_python_name(delegate).await
};View on GitHub (pinned to f4178619ac)
Solutions
- Keep the port in exactly one place — delete `"port"` from `config` and leave `tcp_connection.port` (or the reverse).
- Make sure the surviving port matches the port debugpy actually listens on (`python -m debugpy --listen <port>`).
Example fix
// before
{
"adapter": "Python",
"request": "attach",
"tcp_connection": { "port": 5678 },
"config": { "port": 9000 }
}
// after
{
"adapter": "Python",
"request": "attach",
"tcp_connection": { "host": "127.0.0.1", "port": 5678 }
} Defensive patterns
Strategy: validation
Validate before calling
// reject attach configs that define port in two places, before starting a session
let has_tcp_port = task.tcp_connection.as_ref().is_some_and(|t| t.port.is_some());
let has_config_port = task.config.get("request") == Some("attach") && task.config.get("port").is_some();
if has_tcp_port && has_config_port {
return Err(anyhow!("remove `port` from either tcp_connection or config"));
} Type guard
fn defines_port_once(tcp: &Option<TcpConnection>, config: &serde_json::Value) -> bool {
let in_tcp = tcp.as_ref().is_some_and(|t| t.port.is_some());
let in_config = config.get("port").is_some_and(|v| !v.is_null());
!(in_tcp && in_config)
} Try / catch
Catch at config-load time and surface both port values in the message so the mismatch is obvious; do not attempt a default choice.
Prevention
- Keep the port only in tcp_connection and make it match the debugpy --listen port.
- Parameterize one variable (e.g. 5678) and reference it in both places if configs are generated.
- Lint for duplicate transport keys when configs are committed.
When it happens
Trigger: A Zed Python debug task where `tcp_connection: { "port": 5678 }` and `config: { "port": 9000 }` are both present with `request: "attach"`; also hit when a copied VS Code config keeps its port and the Zed-side port is added afterwards.
Common situations: Migrating launch.json snippets into Zed debug configs; changing the debugpy --listen port on one side but not the other; templates that pre-fill both fields.
Related errors
- Cannot have two different hosts in debug configuration
- debug config not found in mode: {mode}
- No process selected with config that contains {}
- Zed cannot determine how to run this debug scenario. `build`
- Expected exactly one context server configuration
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/0fc4c9c1cfe11b18.
Report an issue: GitHub.