astrid-runtime/astrid · error

MCP gateway is already running at

Error message

MCP gateway is already running at {}

What it means

Fired by prepare_gateway_socket when the gateway socket path exists and a Unix-stream probe successfully connects to it — meaning another live gateway process already owns the endpoint. Binding a second listener would silently steal or fail against the existing owner.

Solutions

  1. Use the already-running gateway instead of starting a new one (`astrid mcp status`)
  2. Stop the existing gateway before restarting
  3. Remove a stale socket only after confirming no process is listening
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:384 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/859e2d0f06a627d1. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:384

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700))?;
    }
    Ok(())
}

/// Bind-time cleanup and endpoint ownership check for a gateway listener.
pub(crate) async fn prepare_gateway_socket(_lifecycle: &GatewayLifecycleLock) -> Result<PathBuf> {
    let path = gateway_socket_path()?;
    let parent = path
        .parent()
        .ok_or_else(|| anyhow::anyhow!("MCP gateway socket path has no parent"))?;
    ensure_private_dir(parent)?;

    if path.exists() {
        if UnixStream::connect(&path).await.is_ok() {
            anyhow::bail!("MCP gateway is already running at {}", path.display());
        }
        // The lifecycle lock excludes every gateway generation. If the
        // pathname survived a crash, this holder is now the only process that
        // may remove and replace it.
        std::fs::remove_file(&path).with_context(|| {
            format!(
                "failed to remove stale MCP gateway socket {}",
                path.display()
            )
        })?;
    }
    Ok(path)
}

/// Wait for a ready gateway, starting one child at most once when absent.
pub(crate) async fn wait_for_gateway(principal: &PrincipalId, format: &str) -> Result<ExitCode> {
    let format = ReadyFormat::parse(format)?;
    let socket = gateway_socket_path()?;

View on GitHub (pinned to affd8760f4)