{"record":{"id":"1f8bb64e3d7535be","repo":"astrid-runtime/astrid","slug":"invalid-mcp-gateway-readiness-metadata-at","errorCode":null,"errorMessage":"invalid MCP gateway readiness metadata at {}","messagePattern":"invalid MCP gateway readiness metadata at (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/mcp/lifecycle.rs","lineNumber":312,"sourceCode":"    let body = match std::fs::read_to_string(path) {\n        Ok(body) => body,\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),\n        Err(error) => {\n            return Err(error).with_context(|| format!(\"failed to read {}\", path.display()));\n        },\n    };\n    let record: GatewayReady = serde_json::from_str(&body).with_context(|| {\n        format!(\n            \"invalid MCP gateway readiness metadata at {}\",\n            path.display()\n        )\n    })?;\n    if record.version != 1\n        || record.pid == 0\n        || record.principal.is_empty()\n        || record.hook_token.is_empty()\n    {\n        anyhow::bail!(\n            \"invalid MCP gateway readiness metadata at {}\",\n            path.display()\n        );\n    }\n    Ok(Some(record))\n}\n\n/// Write readiness metadata without exposing a partial record to attachers.\npub(crate) fn write_gateway_ready(record: &GatewayReady) -> Result<()> {\n    let path = gateway_ready_path()?;\n    let parent = path\n        .parent()\n        .ok_or_else(|| anyhow::anyhow!(\"MCP gateway readiness path has no parent\"))?;\n    ensure_private_dir(parent)?;\n    let temp = path.with_extension(format!(\"ready.tmp.{}\", std::process::id()));\n    let bytes = serde_json::to_vec(record).context(\"failed to encode MCP gateway readiness\")?;\n    std::fs::write(&temp, bytes).with_context(|| format!(\"failed to write {}\", temp.display()))?;\n    #[cfg(unix)]","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/mcp/lifecycle.rs#L294-L330","documentation":"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.","triggerScenarios":"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.","commonSituations":"Gateway crashed between file creation and full write; readiness file format changed between library versions; file manually edited; leftover file from a failed startup.","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"],"exampleFix":"// before\nlet ready = read_gateway_ready()?.unwrap();\n// after\nlet ready = match read_gateway_ready() {\n    Ok(Some(r)) => Some(r),\n    Err(_) | Ok(None) => { wait_for_gateway_ready(timeout)?; read_gateway_ready()? }\n};","handlingStrategy":"retry","validationCode":"fn ready_record_ok(r: &GatewayReady) -> bool {\n    r.version == 1 && r.pid != 0 && !r.principal.is_empty() && !r.hook_token.is_empty()\n}","typeGuard":"fn is_valid_ready(r: &GatewayReady) -> bool { r.version == 1 && r.pid != 0 && !r.principal.is_empty() && !r.hook_token.is_empty() }","tryCatchPattern":"match read_gateway_ready() {\n    Ok(Some(r)) => use(r),\n    Ok(None) | Err(_) => { wait_for_gateway(timeout)?; read_gateway_ready()? }\n}","preventionTips":["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)"],"tags":["lifecycle","mcp","corrupt-state"],"backgroundTag":"schema-validation-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}