astrid-runtime/astrid · error
invalid MCP gateway readiness metadata at {}
Error message
invalid MCP gateway readiness metadata at {} What it means
read_gateway_ready_at validates the gateway readiness record's schema and contents: version must be 1, pid must be non-zero, and principal and hook_token must be non-empty. A record failing any check is malformed and cannot be trusted to connect to or manage the gateway, so it errors instead of returning the record. This protects callers from acting on partially-written or foreign readiness files.
Source
Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:312
let body = match std::fs::read_to_string(path) {
Ok(body) => body,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(error) => {
return Err(error).with_context(|| format!("failed to read {}", path.display()));
},
};
let record: GatewayReady = serde_json::from_str(&body).with_context(|| {
format!(
"invalid MCP gateway readiness metadata at {}",
path.display()
)
})?;
if record.version != 1
|| record.pid == 0
|| record.principal.is_empty()
|| record.hook_token.is_empty()
{
anyhow::bail!(
"invalid MCP gateway readiness metadata at {}",
path.display()
);
}
Ok(Some(record))
}
/// Write readiness metadata without exposing a partial record to attachers.
pub(crate) fn write_gateway_ready(record: &GatewayReady) -> Result<()> {
let path = gateway_ready_path()?;
let parent = path
.parent()
.ok_or_else(|| anyhow::anyhow!("MCP gateway readiness path has no parent"))?;
ensure_private_dir(parent)?;
let temp = path.with_extension(format!("ready.tmp.{}", std::process::id()));
let bytes = serde_json::to_vec(record).context("failed to encode MCP gateway readiness")?;
std::fs::write(&temp, bytes).with_context(|| format!("failed to write {}", temp.display()))?;
#[cfg(unix)]View on GitHub (pinned to affd8760f4)
Solutions
- Delete the malformed readiness file and restart the gateway to regenerate it
- Confirm client and gateway are the same version (record.version must equal 1)
- Wait and retry — the gateway may still be mid-write when you read
- Check that no external process truncates files in the runtime directory
Example fix
// before
let ready = read_gateway_ready()?.unwrap();
// after
let ready = match read_gateway_ready() {
Ok(Some(r)) => Some(r),
Err(_) | Ok(None) => { wait_for_gateway_ready(timeout)?; read_gateway_ready()? }
}; Defensive patterns
Strategy: retry
Validate before calling
fn ready_record_ok(r: &GatewayReady) -> bool {
r.version == 1 && r.pid != 0 && !r.principal.is_empty() && !r.hook_token.is_empty()
} Type guard
fn is_valid_ready(r: &GatewayReady) -> bool { r.version == 1 && r.pid != 0 && !r.principal.is_empty() && !r.hook_token.is_empty() } Try / catch
match read_gateway_ready() {
Ok(Some(r)) => use(r),
Ok(None) | Err(_) => { wait_for_gateway(timeout)?; read_gateway_ready()? }
} Prevention
- Wait for the gateway to signal readiness before reading the file
- Write the readiness record atomically (temp + rename)
- Pin client and gateway to the same version (record version 1)
When it happens
Trigger: read_gateway_ready/remove_gateway_ready_at encounter a readiness file with an unknown version number, pid==0, or empty principal/hook_token — e.g. truncated write or a file produced by an incompatible version.
Common situations: Gateway crashed between file creation and full write; readiness file format changed between library versions; file manually edited; leftover file from a failed startup.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid MCP gateway startup lease 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/1f8bb64e3d7535be.
Report an issue: GitHub.