astrid-runtime/astrid · error

unexpected response shape: {other:?}

Error message

unexpected response shape: {other:?}

What it means

run_issue matches the AdminResponseBody returned for a pair-device issue request and only handles the expected issued-response variant; any other variant falls into the `other` catch-all and bails with the debug-formatted response. This indicates a protocol/shape mismatch between what the CLI requested and what the daemon replied with.

Source

Thrown at crates/astrid-cli/src/commands/pair_device.rs:153

    let body = into_result(resp)?;
    match body {
        AdminResponseBody::PairToken(issued) => {
            if args.raw {
                println!("{}", issued.token);
            } else {
                println!(
                    "{} {} (principal: {}, scope: {}, label: {})",
                    Theme::success("issued"),
                    issued.token.bold(),
                    issued.principal,
                    scope_summary,
                    issued.label.as_deref().unwrap_or("-"),
                );
                println!("expires at unix epoch {}", issued.expires_at_epoch);
            }
            Ok(ExitCode::SUCCESS)
        },
        other => anyhow::bail!("unexpected response shape: {other:?}"),
    }
}

async fn run_list(args: ListArgs) -> Result<ExitCode> {
    let principal = context::resolve_agent(args.principal.as_deref())?;
    let mut client = connect_as_active_agent().await?;
    let resp = client
        .request(AdminRequestKind::PairDeviceList { principal })
        .await
        .context("auth.pair.list request failed")?;
    let body = into_result(resp)?;
    match body {
        AdminResponseBody::PairDeviceListed(devices) => {
            if args.json {
                println!("{}", serde_json::to_string_pretty(&devices)?);
            } else if devices.is_empty() {
                println!("{}", Theme::dimmed("no paired devices"));
            } else {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Update the astrid CLI and daemon to matching versions so AdminResponseBody shapes agree.
  2. Log the full `other` payload ({other:?}) and compare against the AdminResponseBody enum to identify the mismatched variant.
  3. Confirm the request kind/topic maps to the pair-device issue response (not list/revoke).
  4. Add an explicit match arm for the new variant if the daemon intentionally returns it.

Example fix

// before
other => anyhow::bail!("unexpected response shape: {other:?}"),
// after
AdminResponseBody::Error { message } => anyhow::bail!("issue failed: {message}"),
other => anyhow::bail!("unexpected response shape: {other:?}"),
Defensive patterns

Strategy: type-guard

Validate before calling

// confirm the request/response kind pair before matching the body
if !matches!(resp.kind(), AdminResponseKind::PairDeviceIssued) {
    anyhow::bail!("pair-device issue request mismatched with response kind {:?}", resp.kind());
}

Type guard

fn as_issue_response(body: &AdminResponseBody) -> Option<&PairDeviceIssued> {
    match body {
        AdminResponseBody::PairDeviceIssued(i) => Some(i),
        _ => None,
    }
}

Try / catch

match run_issue(args).await {
    Ok(code) => code,
    Err(e) if e.to_string().starts_with("unexpected response shape") => {
        eprintln!("CLI/daemon protocol skew: {e:#}; update astrid CLI and daemon to matching versions");
        ExitCode::FAILURE
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Sending a PairDevice issue request whose response body is an AdminResponseBody variant other than the expected issued/credential variant — e.g. an error body, a list/revoked body, or a variant added by a newer daemon — reaching the `other => anyhow::bail!` arm in run_issue.

Common situations: CLI and daemon version skew (daemon returns a new response shape); request routed to the wrong IPC topic so an unrelated response arrives; daemon returned an error encoded as a different body variant; corrupted or mixed-up responses on a shared connection.

Related errors


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