zeroclaw-labs/zeroclaw · error · anyhow::Error

Port {port} is already in use, so the gateway could not star

Error message

Port {port} is already in use, so the gateway could not start.

What it means

The gateway HTTP listener could not bind because the requested address (host:port) is already taken by another process. The code detects this by walking the error chain with is_addr_in_use_error (downcasting to std::io::Error with kind AddrInUse) and replaces the raw io error with an actionable message that includes a restart hint port from available_gateway_restart_hint_port.

Source

Thrown at src/main.rs:8132

    // can self-respawn after the listener is released. Must mirror the same
    // call in the Daemon branch.
    zeroclaw_runtime::restart::record_launch();
    // Standalone gateway (no daemon supervisor): pass None for reload_tx so
    // /admin/reload returns 503 with a clear "no supervisor; restart
    // manually" message, None for tui_registry (no TUI socket), and None
    // for canvas_store so the gateway falls back to its own default.
    let result = Box::pin(gateway::run_gateway(
        host, port, config, tx, None, None, None, None, None, None,
    ))
    .await;
    // Self-respawn after the listener is released, if an in-app upgrade
    // requested it. No-op when no respawn was requested or on supervised
    // restart modes.
    zeroclaw_runtime::restart::respawn_if_requested();
    match result {
        Err(err) if is_addr_in_use_error(&err) => {
            let restart_port = available_gateway_restart_hint_port(host, port);
            anyhow::bail!(
                "{}",
                gateway_addr_in_use_message(host, port, &default_host, default_port, restart_port)
            );
        }
        other => other,
    }
}

#[cfg(not(feature = "gateway"))]
#[allow(clippy::unused_async)]
async fn run_gateway_if_enabled(
    _host: &str,
    _port: u16,
    _config: zeroclaw::config::Config,
    _tx: Option<tokio::sync::broadcast::Sender<serde_json::Value>>,
) -> anyhow::Result<()> {
    anyhow::bail!("Gateway feature is not enabled. Rebuild with --features gateway")
}

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Free the port: stop the other process (`lsof -i :<port>` / `ss -ltnp` to find it)
  2. Use the restart hint port the error message suggests, or change gateway port in the config and restart
  3. If it is a respawn race after a restart, wait a moment and start again — the old listener releases the socket
  4. Set a distinct port per instance when running multiple gateways

Example fix

# before
port = 8080   # already bound by another process

# after
port = 8081   # or kill the holder: kill $(lsof -t -i :8080)
Defensive patterns

Strategy: validation

Validate before calling

// Probe the bind before handing the port to the gateway:
use tokio::net::TcpListener;
match TcpListener::bind((host, port)).await {
    Ok(_) => { /* port free; drop the probe listener immediately */ }
    Err(e) if e.kind() == std::io::ErrorKind::AddrInUse => {
        // pick another port or surface a clear message before starting
    }
    Err(e) => return Err(e.into()),
}

Type guard

// Reuse the same chain-walking check the source uses:
fn is_addr_in_use_error(err: &anyhow::Error) -> bool {
    err.chain().any(|c| c.downcast_ref::<std::io::Error>()
        .map_or(false, |io| io.kind() == std::io::ErrorKind::AddrInUse))
}

Try / catch

// Catch on the serve call, branch on AddrInUse via the chain (as main.rs does),
// then either retry with the suggested hint port or fail with the actionable message.

Prevention

When it happens

Trigger: Starting zeroclaw while another zeroclaw instance, a respawned child, or any unrelated process (dev server, proxy) already listens on the configured gateway host:port. Also happens when a supervised restart races the old process shutting down.

Common situations: Two gateway instances configured with the same port; a previous instance that did not fully exit (orphan/respawn race); another service (nginx, node dev server) occupying the port; docker port mappings colliding.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/f72dc2c06e3a9faa. Report an issue: GitHub.