{"record":{"id":"8b48b2e4e393ae11","repo":"astrid-runtime/astrid","slug":"mcp-gateway-is-already-bound-to-principal-no","errorCode":null,"errorMessage":"MCP gateway is already bound to principal '{}', not '{}'","messagePattern":"MCP gateway is already bound to principal '(.+?)', not '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/mcp/lifecycle.rs","lineNumber":413,"sourceCode":"    }\n    Ok(path)\n}\n\n/// Wait for a ready gateway, starting one child at most once when absent.\npub(crate) async fn wait_for_gateway(principal: &PrincipalId, format: &str) -> Result<ExitCode> {\n    let format = ReadyFormat::parse(format)?;\n    let socket = gateway_socket_path()?;\n    let deadline = Instant::now()\n        .checked_add(SPAWNED_READY_TIMEOUT)\n        .unwrap_or_else(Instant::now);\n    let mut spawned = false;\n    loop {\n        if let Some(record) = read_gateway_ready()? {\n            // A gateway is bound to the principal that minted its ready\n            // record. Each attach must present that same process principal\n            // and the gateway's token before an uplink is selected.\n            if record.principal != principal.to_string() {\n                anyhow::bail!(\n                    \"MCP gateway is already bound to principal '{}', not '{}'\",\n                    record.principal,\n                    principal\n                );\n            }\n            match astrid_core::local_transport::connect_outcome(&socket)\n                .await\n                .context(\"failed to inspect MCP gateway endpoint\")?\n            {\n                astrid_core::local_transport::ConnectOutcome::Connected(stream) => {\n                    request_gateway_control(stream, &record, GatewayControlOperation::Health)\n                        .await\n                        .context(\"MCP gateway cannot prove a recoverable daemon uplink\")?;\n                    emit_ready(format, &record)?;\n                    return Ok(ExitCode::SUCCESS);\n                },\n                astrid_core::local_transport::ConnectOutcome::Absent\n                | astrid_core::local_transport::ConnectOutcome::Stale","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/mcp/lifecycle.rs#L395-L431","documentation":"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.","triggerScenarios":"Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:413 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Connect as the principal the gateway was started for","Stop the current gateway and start one under the desired principal","Run separate gateways per principal if isolation is needed"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}