astrid-runtime/astrid · error

MCP gateway is already bound to principal

Error message

MCP gateway is already bound to principal '{}', not '{}'

What it means

Fired by wait_for_gateway when a ready gateway is reachable but its ready record is bound to a different principal than the one requesting attachment. Gateways are single-principal; attaching another principal's client would cross trust boundaries.

Solutions

  1. Connect as the principal the gateway was started for
  2. Stop the current gateway and start one under the desired principal
  3. Run separate gateways per principal if isolation is needed
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:413 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/8b48b2e4e393ae11. Report an issue: GitHub.

Appendix: source

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

    }
    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()?;
    let deadline = Instant::now()
        .checked_add(SPAWNED_READY_TIMEOUT)
        .unwrap_or_else(Instant::now);
    let mut spawned = false;
    loop {
        if let Some(record) = read_gateway_ready()? {
            // A gateway is bound to the principal that minted its ready
            // record. Each attach must present that same process principal
            // and the gateway's token before an uplink is selected.
            if record.principal != principal.to_string() {
                anyhow::bail!(
                    "MCP gateway is already bound to principal '{}', not '{}'",
                    record.principal,
                    principal
                );
            }
            match astrid_core::local_transport::connect_outcome(&socket)
                .await
                .context("failed to inspect MCP gateway endpoint")?
            {
                astrid_core::local_transport::ConnectOutcome::Connected(stream) => {
                    request_gateway_control(stream, &record, GatewayControlOperation::Health)
                        .await
                        .context("MCP gateway cannot prove a recoverable daemon uplink")?;
                    emit_ready(format, &record)?;
                    return Ok(ExitCode::SUCCESS);
                },
                astrid_core::local_transport::ConnectOutcome::Absent
                | astrid_core::local_transport::ConnectOutcome::Stale

View on GitHub (pinned to affd8760f4)