astrid-runtime/astrid · error

unexpected distro lock response: {other:?}

Error message

unexpected distro lock response: {other:?}

What it means

load_lock_from_daemon sends an AdminRequestKind::DistroLockGet request to the kernel daemon and pattern-matches on the reply. The daemon is expected to answer with AdminResponseBody::DistroLock or AdminResponseBody::Error; any other AdminResponseBody variant indicates a protocol mismatch between CLI and daemon (wrong daemon version, mismatched request kind, or deserialization drift). This fallback arm wraps the actual variant in anyhow with a debug dump so the developer can see what came back.

Source

Thrown at crates/astrid-cli/src/commands/distro/lock.rs:162

pub(crate) fn provenance_digest(provenance: &DistroProvenance) -> anyhow::Result<String> {
    let bytes = serde_json::to_vec(provenance).context("encode distro provenance")?;
    Ok(format!("blake3:{}", blake3::hash(&bytes).to_hex()))
}

/// Read the target principal's durable distro record through the daemon.
pub(crate) async fn load_lock_from_daemon(
    principal: &PrincipalId,
) -> anyhow::Result<Option<DistroLock>> {
    let mut client = crate::admin_client::connect_as_active_agent().await?;
    let response = client
        .request(AdminRequestKind::DistroLockGet {
            principal: principal.clone(),
        })
        .await?;
    match response {
        AdminResponseBody::DistroLock(lock) => Ok((*lock).map(from_provenance)),
        AdminResponseBody::Error(error) => Err(anyhow::anyhow!(error)),
        other => Err(anyhow::anyhow!(
            "unexpected distro lock response: {other:?}"
        )),
    }
}

/// Replace the target principal's durable distro record with an optimistic
/// compare-and-swap. A missing current record is an intentional create.
pub(crate) async fn write_lock_to_daemon(
    principal: &PrincipalId,
    lock: &DistroLock,
) -> anyhow::Result<()> {
    let mut client = crate::admin_client::connect_as_active_agent().await?;
    let current = client
        .request(AdminRequestKind::DistroLockGet {
            principal: principal.clone(),
        })
        .await?;
    let current = match current {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Restart the astrid daemon so the CLI and daemon binaries are from the same build/version.
  2. Rebuild/reinstall both CLI and daemon from the same commit (cargo build --workspace or your release pipeline) and retry.
  3. Read the {other:?} debug dump in the message to identify which AdminResponseBody variant was actually returned and check the daemon's admin response routing for that request kind.
  4. If the daemon is an older deployment, upgrade it to a version whose DistroLockGet handler returns DistroLock/Error variants the CLI understands.

Example fix

// before (older daemon returns Success for a get)
let response = client.request(AdminRequestKind::DistroLockGet { principal }).await?;
AdminResponseBody::DistroLock(lock) => Ok((*lock).map(from_provenance)),
// after: also accept Success-with-no-body style responses or version-check first
let version = client.hello().await?;
anyhow::ensure!(version.is_compatible_with(env!("CARGO_PKG_VERSION")), "daemon/CLI version mismatch: {version}");
AdminResponseBody::DistroLock(lock) => Ok((*lock).map(from_provenance)),
Defensive patterns

Strategy: try-catch

Validate before calling

let v = client.hello().await?;
anyhow::ensure!(v.supports(AdminRequestKind::DistroLockGetMarker), "daemon does not support DistroLockGet (version {v})");

Type guard

fn as_distro_lock(r: &AdminResponseBody) -> Option<&Option<DistroProvenance>> {
    match r { AdminResponseBody::DistroLock(l) => Some(l), _ => None }
}

Try / catch

match load_lock_from_daemon(&principal).await {
    Ok(lock) => lock,
    Err(e) if e.to_string().contains("unexpected distro lock response") => {
        eprintln!("CLI/daemon version mismatch — restart the daemon");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling load_lock_from_daemon (directly or via regenerate_distro_lock) against a daemon that returns a response variant other than DistroLock or Error for a DistroLockGet request — e.g. AdminResponseBody::Success, an unrelated payload variant, or an empty/unknown variant from an older or newer daemon binary.

Common situations: Running a newer astrid CLI against an older running daemon (or vice versa) whose AdminResponseBody enum gained/lost variants; a daemon bug routing the DistroLockGet reply to the wrong response constructor; stale daemon process not restarted after an upgrade.

Related errors


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