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

  1. Delete the malformed readiness file and restart the gateway to regenerate it
  2. Confirm client and gateway are the same version (record.version must equal 1)
  3. Wait and retry — the gateway may still be mid-write when you read
  4. 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

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/1f8bb64e3d7535be. Report an issue: GitHub.