atuinsh/atuin · error

id should be 16 bytes

Error message

id should be 16 bytes

What it means

The daemon search engine streams results from the background atuin daemon over gRPC; each id is a 16-byte UUID in wire form. The client converts each id with id.as_slice().try_into::<[u8; 16]>() and expects success. A response carrying an id whose byte length differs (short, long, corrupt) violates the protocol and panics with 'id should be 16 bytes' inside the search flow.

Source

Thrown at crates/atuin/src/command/client/search/engines/daemon.rs:199

        let mut ids = Vec::with_capacity(200);
        span!(Level::TRACE, "daemon_search.resp")
            .in_scope(async || -> Result<()> {
                while let Some(response) = stream.message().await? {
                    let span2 = span!(
                        Level::TRACE,
                        "daemon_search.resp.item",
                        query_id = response.query_id
                    );
                    let span2_guard = span2.enter();
                    // Only process if the query_id matches (prevents stale responses)
                    if response.query_id == query_id {
                        let uuids = response
                            .ids
                            .iter()
                            .map(|id| {
                                let bytes: [u8; 16] =
                                    id.as_slice().try_into().expect("id should be 16 bytes");
                                Uuid::from_bytes(bytes).as_simple().to_string()
                            })
                            .collect::<Vec<_>>();
                        ids.extend(uuids);
                    }
                    drop(span2_guard);
                    drop(span2);
                }
                Ok(())
            })
            .await?;
        drop(span);

        if ids.is_empty() {
            debug!(query = %query, results = 0, "[daemon-client] empty results");
            return Ok(Vec::new());
        }

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Restart the daemon so client and daemon run the same atuin version (kill the stale process; it autostarts on next search)
  2. Verify client and daemon come from the same install: compare atuin --version with the daemon's version/logs
  3. If it persists, report it with daemon logs — a non-16-byte id is a protocol violation bug

Example fix

// before
let bytes: [u8; 16] = id.as_slice().try_into().expect("id should be 16 bytes");

// after — skip malformed ids instead of crashing the TUI
let Ok(bytes) = <[u8; 16]>::try_from(id.as_slice()) else {
    tracing::warn!(len = id.len(), "daemon sent a non-16-byte id; skipping");
    continue;
};
Defensive patterns

Strategy: validation

Validate before calling

// drop malformed ids before conversion
let uuids: Vec<_> = response
    .ids
    .iter()
    .filter(|id| id.len() == 16)
    .map(|id| Uuid::from_bytes(id.as_slice().try_into().unwrap()))
    .collect();

Type guard

fn is_uuid_bytes(id: &[u8]) -> bool {
    id.len() == 16
}

Try / catch

// isolate per-item conversion so one bad id fails a single search, not the TUI
let uuids: Vec<_> = response.ids.iter().filter_map(|id| {
    <[u8; 16]>::try_from(id.as_slice())
        .ok()
        .map(|b| Uuid::from_bytes(b).as_simple().to_string())
}).collect();

Prevention

When it happens

Trigger: full_query() processing a SearchResponse whose ids contain anything other than exactly 16 bytes: a client/daemon version mismatch that changes the id encoding, a truncated or corrupted gRPC message, or a daemon bug emitting malformed ids.

Common situations: Upgrading the atuin CLI while the old daemon keeps running (client and daemon from different versions); a stale daemon socket after a partial upgrade; protocol drift between atuin components.

Related errors


AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16). Data as JSON: /api/errors/cf5d8f17a8d1db0e. Report an issue: GitHub.