astrid-runtime/astrid · error
invalid MCP gateway startup lease at {}
Error message
invalid MCP gateway startup lease at {} What it means
read_gateway_startup_lease parses the gateway's startup lease file and sanity-checks its contents. A lease is considered invalid when the gateway PID is 0 or the recorded gateway executable path is empty/missing — meaning the file exists but cannot describe a live, locatable gateway. The corrupt/invalid lease is treated as an error rather than silently ignored so callers can clean up deterministically.
Source
Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:170
pub(crate) fn read_gateway_startup_lease() -> Result<Option<GatewayStartupLease>> {
let path = gateway_startup_lease_path()?;
match std::fs::read(&path) {
Ok(bytes) => {
let lease: GatewayStartupLease = serde_json::from_slice(&bytes).with_context(|| {
format!("invalid MCP gateway startup lease at {}", path.display())
})?;
if lease.version != 1
|| lease.principal.is_empty()
|| lease.boot_token.len() != 32
|| lease.supervisor_pid == 0
|| lease.gateway_pid.is_some_and(|pid| pid == 0)
|| lease
.gateway_exe
.as_ref()
.is_none_or(|path| path.as_os_str().is_empty())
{
anyhow::bail!("invalid MCP gateway startup lease at {}", path.display());
}
Ok(Some(lease))
},
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(error) => Err(error).with_context(|| format!("failed to read {}", path.display())),
}
}
pub(crate) fn write_gateway_startup_lease(lease: &GatewayStartupLease) -> Result<()> {
let path = gateway_startup_lease_path()?;
let parent = path
.parent()
.ok_or_else(|| anyhow::anyhow!("MCP gateway startup lease path has no parent"))?;
ensure_private_dir(parent)?;
let temp = path.with_extension(format!("starting.tmp.{}", std::process::id()));
let bytes = serde_json::to_vec(lease).context("failed to encode MCP gateway startup lease")?;
std::fs::write(&temp, bytes).with_context(|| format!("failed to write {}", temp.display()))?;
#[cfg(unix)]View on GitHub (pinned to affd8760f4)
Solutions
- Delete the invalid startup lease file and restart the gateway so a fresh lease is written
- Verify no gateway process is running (the stale PID may be dead) then remove leftover lease files under the runtime dir
- Upgrade/downgrade so reader and writer agree on the lease format
- Check disk health if truncation recurs
Example fix
// before
// assuming lease file is valid
let lease = read_gateway_startup_lease()?;
// after
match read_gateway_startup_lease() {
Ok(lease) => lease,
Err(_) => { let _ = std::fs::remove_file(gateway_startup_lease_path()?); None }
} Defensive patterns
Strategy: try-catch
Validate before calling
if let Ok(bytes) = std::fs::read(&lease_path) {
if let Ok(lease) = serde_json::from_slice::<GatewayStartupLease>(&bytes) {
if lease.gateway_pid == Some(0) || lease.gateway_exe.as_ref().is_none_or(|p| p.as_os_str().is_empty()) {
let _ = std::fs::remove_file(&lease_path); // clean invalid lease first
}
}
} Type guard
fn lease_is_valid(l: &GatewayStartupLease) -> bool {
!l.gateway_pid.is_some_and(|pid| pid == 0)
&& l.gateway_exe.as_ref().is_some_and(|p| !p.as_os_str().is_empty())
} Try / catch
match read_gateway_startup_lease() {
Ok(lease) => use(lease),
Err(e) if e.to_string().contains("invalid MCP gateway startup lease") => {
let _ = std::fs::remove_file(gateway_startup_lease_path()?);
restart_gateway()
}
Err(e) => return Err(e),
} Prevention
- Write lease files atomically (write temp + rename) to avoid truncation
- Clean stale leases on unclean-shutdown detection
- Keep lease format versioned
When it happens
Trigger: wait_for_gateway/stop_gateway/stop_startup_gateway read a lease file whose gateway_pid is 0, gateway_exe is empty, or equivalent malformed fields; partially written or truncated lease file.
Common situations: A previous gateway crashed mid-write leaving a truncated lease; lease file edited or corrupted on disk; version mismatch where an older gateway wrote a lease shape a newer reader rejects; leftover lease from an unclean machine shutdown.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- invalid MCP gateway readiness metadata at {}
- MCP gateway startup generation changed before cleanup
- MCP gateway readiness changed before cleanup at {}
- MCP gateway lock path has no parent
- MCP gateway startup lease path has no parent
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/1cda3bd9c11bdc5c.
Report an issue: GitHub.