astrid-runtime/astrid · error
shutdown stage gateway.startup_identity: lease disappeared
Error message
shutdown stage gateway.startup_identity: lease disappeared
What it means
`stop_startup_gateway` shuts down a gateway that is still starting. It reads the on-disk startup lease a second time and compares it to the lease observed earlier; this error is thrown when the lease file has disappeared, meaning the startup generation ended (crashed, completed and replaced by the ready record, or cleaned up by another process) between the two reads.
Solutions
- Re-run the stop command; the transient startup generation has ended, so re-evaluating state will follow the normal stop path.
- Check the ready file/socket: if the gateway finished starting, it will be stopped via the normal (non-startup) path on retry.
- Avoid racing multiple stop commands; run one shutdown at a time.
- Inspect gateway logs to confirm the starting process crashed or completed during shutdown.
Example fix
// before astrid mcp gateway stop # single attempt may hit transient lease removal // after astrid mcp gateway stop || astrid mcp gateway stop
Defensive patterns
Strategy: retry
Validate before calling
// Check current startup state before stopping
let leasing = read_gateway_startup_lease()?;
eprintln!("startup lease present: {}", leasing.is_some()); Try / catch
if let Err(e) = stop_gateway().await {
if e.to_string().contains("lease disappeared") {
eprintln!("startup generation ended mid-stop; retrying");
stop_gateway().await?;
} else { return Err(e); }
} Prevention
- Avoid stopping exactly while startup is in flight; wait for ready
- Run a single stop command at a time
- Monitor gateway logs to know when startup completed or crashed
- Retry transient lifecycle errors once before escalating
When it happens
Trigger: The startup lease file (`mcp-gateway.starting`) is deleted between `stop_gateway` reading it and `stop_startup_gateway` re-reading it — e.g. the starting gateway crashed or finished starting (lease removed/converted to ready) concurrently, or a stale-startup cleanup ran in between.
Common situations: Stopping the gateway at the exact moment its startup completes or fails; a concurrent `stop` or cleanup process removing the lease; the starting gateway process dying mid-startup.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- shutdown stage gateway.startup_stop: lifecycle changed
- invalid MCP gateway readiness metadata at
- invalid MCP gateway startup lease at
- MCP gateway lock path has no parent
- MCP gateway readiness changed before cleanup at
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5ff0bb7a25764d98.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:605
.await
{
anyhow::bail!(
"shutdown stage gateway.process_reap: authenticated gateway PID {} did not exit",
record.pid
);
}
remove_dead_gateway_markers(&record).await
}
async fn stop_startup_gateway(lease: &GatewayStartupLease) -> Result<()> {
let Some(gateway_pid) = lease.gateway_pid else {
anyhow::bail!("shutdown stage gateway.startup_identity: lease has no gateway PID");
};
let Some(gateway_exe) = lease.gateway_exe.as_deref() else {
anyhow::bail!("shutdown stage gateway.startup_identity: lease has no executable");
};
let current = read_gateway_startup_lease()?.ok_or_else(|| {
anyhow::anyhow!("shutdown stage gateway.startup_identity: lease disappeared")
})?;
if current != *lease {
anyhow::bail!("shutdown stage gateway.startup_identity: startup generation changed");
}
let outcome =
crate::commands::daemon_control::terminate_known(gateway_pid, Some(gateway_exe)).await;
if !matches!(
outcome,
crate::commands::daemon_control::KillOutcome::TermExited
| crate::commands::daemon_control::KillOutcome::KilledExited
) {
anyhow::bail!(
"shutdown stage gateway.startup_reap: starting gateway PID {gateway_pid} is {outcome:?}"
);
}
Ok(())
}View on GitHub (pinned to affd8760f4)