astrid-runtime/astrid · error

unexpected daemon response: {other:?}

Error message

unexpected daemon response: {other:?}

What it means

Raised by `list_capsules` when the daemon's reply to `GetCapsuleMetadata` is neither `CapsuleMetadata` nor `Error` — an unanticipated `KernelResponse` variant. It means the daemon's response no longer matches the protocol the CLI expects, usually because of a version mismatch between the two binaries.

Source

Thrown at crates/astrid-cli/src/commands/capsule/list.rs:27

use colored::Colorize;

#[cfg(test)]
use super::meta::scan_installed_capsules_in_home_for_with_layout;
use crate::theme::Theme;

/// List all installed capsules with their provides/requires metadata.
///
/// In default mode, shows a compact one-line-per-capsule view with capability
/// counts. With `--verbose`, expands each capsule to show the full capability
/// list and install source.
pub(crate) async fn list_capsules(verbose: bool) -> anyhow::Result<()> {
    let mut client = crate::socket_client::connect_kernel_for_workspace(None).await?;
    let entries = match client.request(KernelRequest::GetCapsuleMetadata).await? {
        KernelResponse::CapsuleMetadata(entries) => entries,
        KernelResponse::Error(message) => {
            anyhow::bail!("daemon rejected capsule metadata request: {message}")
        },
        other => anyhow::bail!("unexpected daemon response: {other:?}"),
    };

    if entries.is_empty() {
        println!("{}", Theme::info("No capsules installed."));
        return Ok(());
    }

    println!(
        "{} ({})",
        Theme::header("Installed Capsules"),
        entries.len()
    );
    println!("{}", Theme::separator());
    for entry in &entries {
        let source = entry
            .source_id
            .map_or_else(|| "unloaded".to_owned(), |id| id.to_string());
        if verbose {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Restart the daemon so both sides speak the same protocol version.
  2. Upgrade the daemon binary to match your CLI version.
  3. Inspect the printed `{other:?}` payload to see which variant arrived.
  4. Clean up stale socket files and ensure a single daemon instance owns the workspace.

Example fix

// before
astrid capsule list
// error: unexpected daemon response: CapsuleMetadataV1([...])

// after
astrid daemon restart  # daemon now matches CLI protocol
astrid capsule list
Defensive patterns

Strategy: type-guard

Type guard

fn as_metadata(resp: KernelResponse) -> Result<Vec<CapsuleMetadataEntry>, KernelResponse> {
    match resp {
        KernelResponse::CapsuleMetadata(entries) => Ok(entries),
        other => Err(other),
    }
}

Try / catch

match list_capsules(verbose).await {
    Ok(()) => {},
    Err(e) if e.to_string().starts_with("unexpected daemon response") => {
        eprintln!("{e:#}\nDaemon protocol mismatch - restart or upgrade the daemon.");
        std::process::exit(1);
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running `astrid capsule list` against a daemon that answers GetCapsuleMetadata with an unexpected variant (e.g. plain Success, or a newer/older protocol payload), produced by CLI/daemon version skew, stale sockets, or non-standard daemon builds.

Common situations: CLI upgraded while an old daemon process is still running; stale socket file pointing at a dead/replaced daemon; multiple daemon instances; experimenting with a forked daemon.

Related errors


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