{"record":{"id":"7068afce80d09819","repo":"astrid-runtime/astrid","slug":"another-mcp-gateway-startup-or-lifecycle-is-alread","errorCode":null,"errorMessage":"another MCP gateway startup or lifecycle is already active","messagePattern":"another MCP gateway startup or lifecycle is already active","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/mcp/gateway.rs","lineNumber":442,"sourceCode":"impl AttachReservation {\n    async fn install(\n        self,\n        state: &GatewayState,\n        host_session_id: String,\n        slot: AttachSlot,\n    ) -> OwnedSemaphorePermit {\n        let Self { admission, permit } = self;\n        state.install_slot(host_session_id, slot).await;\n        drop(admission);\n        permit\n    }\n}\n\n/// Run the durable MCP gateway until it is terminated.\npub(crate) async fn run(principal: Option<&str>) -> Result<ExitCode> {\n    let caller = super::lifecycle::resolve_principal(principal)?;\n    let lifecycle = try_acquire_gateway_lifecycle()?.ok_or_else(|| {\n        anyhow::anyhow!(\"another MCP gateway startup or lifecycle is already active\")\n    })?;\n    let daemon_root = std::env::current_dir().context(\"failed to read MCP gateway cwd\")?;\n\n    let boot_token = mint_boot_token();\n    let gateway_exe = std::env::current_exe()\n        .and_then(std::fs::canonicalize)\n        .context(\"failed to resolve MCP gateway executable identity\")?;\n    let startup_lease = GatewayStartupLease {\n        version: 1,\n        principal: caller.to_string(),\n        boot_token: boot_token.clone(),\n        supervisor_pid: std::process::id(),\n        gateway_pid: Some(std::process::id()),\n        gateway_exe: Some(gateway_exe),\n    };\n    write_gateway_startup_lease(&startup_lease)?;\n    let mut lease_guard = StartupLeaseGuard {\n        boot_token: boot_token.clone(),","sourceCodeStart":424,"sourceCodeEnd":460,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/mcp/gateway.rs#L424-L460","documentation":"`mcp gateway run` acquires an exclusive advisory lifecycle lock (`try_acquire_gateway_lifecycle`) before starting the durable gateway. If the lock is already held, this error is thrown to prevent two gateway processes (or a startup and a shutdown) from owning the same socket, readiness file, and state directory simultaneously.","triggerScenarios":"Running `astrid mcp gateway run` while another gateway instance already holds the lifecycle lock file (mcp-gateway.lifecycle.lock); a stale lock left by a crashed gateway whose OS-level advisory lock was not released or is held by a lingering supervisor; invoking run and stop/start concurrently.","commonSituations":"Launching the gateway twice in two terminals; a systemd/daemon supervisor auto-restarting the gateway while a manual instance runs; a hung prior gateway process still alive holding the lock; running the command from scripts that race at boot.","solutions":["Check if a gateway is already running (look for the socket / `mcp-gateway.ready` file or the process holding the lifecycle lock) and use it instead of starting a new one.","Stop the existing gateway first (`stop_gateway`) and retry the run.","Find and terminate a hung gateway process (`ps aux | grep mcp-gateway`), then verify the lock is released and retry.","Ensure only one supervisor (daemon, systemd unit, or script) is responsible for starting the gateway."],"exampleFix":"// before\nastrid mcp gateway run   # fails if already running\n// after\nastrid mcp gateway stop || true\nastrid mcp gateway run","handlingStrategy":"fallback","validationCode":"// Check an existing gateway before starting\nlet already = std::path::Path::new(&socket_path).exists();\nif already { eprintln!(\"gateway already running\"); return Ok(()); }","typeGuard":null,"tryCatchPattern":"match try_acquire_gateway_lifecycle()? {\n    Some(lifecycle) => start_gateway(lifecycle).await,\n    None => attach_to_existing_gateway().await, // fall back to attach\n}","preventionTips":["Use a single supervisor (systemd/daemon) to own gateway startup","Attach to a running gateway instead of starting a second one","Stop the gateway before launching a new instance","Check for the socket/ready file in scripts before calling run"],"tags":["mcp","gateway","lock-contention","singleton"],"backgroundTag":"address-already-in-use","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"}