astrid-runtime/astrid · error

daemon returned an unexpected status response

Error message

daemon returned an unexpected status response

What it means

The doctor command sends a KernelRequest::Status over the daemon socket and matches on the reply. If the daemon replies with any KernelResponse variant other than Status or Error, this anyhow error is thrown. It means the daemon is reachable and answered, but with a response type the doctor's status check does not understand.

Source

Thrown at crates/astrid-cli/src/commands/doctor.rs:244

async fn daemon_roundtrip() -> Result<()> {
    let mut client = tokio::time::timeout(
        Duration::from_secs(5),
        crate::socket_client::connect_kernel_for_workspace(None),
    )
    .await
    .map_err(|_| anyhow::anyhow!("connection timed out after 5s"))??;
    match tokio::time::timeout(
        Duration::from_secs(5),
        client.request(KernelRequest::GetStatus),
    )
    .await
    .map_err(|_| anyhow::anyhow!("daemon response timed out after 5s"))??
    {
        KernelResponse::Status(_) => Ok(()),
        KernelResponse::Error(message) => {
            Err(anyhow::anyhow!("daemon rejected status request: {message}"))
        },
        _ => Err(anyhow::anyhow!(
            "daemon returned an unexpected status response"
        )),
    }
}

/// Query the daemon for agent-loop readiness over the same socket the
/// other daemon-dependent checks use. Rides the existing
/// `astrid.v1.request.` ingress allowlist prefix — no capsule change needed.
async fn agent_readiness() -> Result<astrid_core::kernel_api::AgentLoopReadiness> {
    let mut client = tokio::time::timeout(
        Duration::from_secs(5),
        crate::socket_client::connect_kernel_for_workspace(None),
    )
    .await
    .map_err(|_| anyhow::anyhow!("connection timed out after 5s"))??;
    match tokio::time::timeout(
        Duration::from_secs(5),
        client.request(KernelRequest::GetAgentReadiness),

View on GitHub (pinned to affd8760f4)

Solutions

  1. Restart the daemon so its protocol version matches the CLI binary
  2. Rebuild/reinstall astrid-cli and the daemon from the same source revision
  3. Check for a stale socket file from a previous daemon and remove it before restarting
  4. Add a protocol/version handshake to KernelRequest::Status handling to fail fast on mismatch

Example fix

// before
KernelResponse::Status(_) => Ok(()),
// after
KernelResponse::Status(_) => Ok(()),
KernelResponse::Pong => Ok(()), // accept variants a legacy daemon may return
Defensive patterns

Strategy: try-catch

Type guard

fn is_status_response(resp: &KernelResponse) -> bool { matches!(resp, KernelResponse::Status(_)) }

Try / catch

match daemon_roundtrip().await {
    Ok(()) => { /* healthy */ }
    Err(e) if e.to_string().contains("unexpected status response") => {
        // treat as version skew: advise daemon restart
    }
    Err(e) => eprintln!("doctor failed: {e:#}"),
}

Prevention

When it happens

Trigger: Running `astrid doctor`'s daemon_roundtrip check while the daemon (or an intermediary protocol layer) returns an unexpected variant such as AgentReadiness or another non-Status response to a Status request, typically due to a CLI/daemon version mismatch.

Common situations: A daemon built from a different commit or older version is still running on the socket after an upgrade; a new CLI sends Status but the old daemon responds with a shape the CLI doesn't map for that request.

Related errors


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