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

  1. Keep the port in exactly one place — delete `"port"` from `config` and leave `tcp_connection.port` (or the reverse).
  2. 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

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


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/0fc4c9c1cfe11b18. Report an issue: GitHub.