atuinsh/atuin · error
stored value is a valid CommandCapture
Error message
stored value is a valid CommandCapture
What it means
`get()` in the fjall output-capture backend reads a stored value and calls `ActiveSchema::deserialize_value`, expecting all stored values to be valid `CommandCapture` blobs written by the same schema. Panicking means a value in the keyspace cannot be deserialized — corrupted data or a schema/version mismatch between writer and reader.
Source
Thrown at crates/atuin-daemon/src/output_capture/backend/fjall/mod.rs:91
Ok(())
}
// Another writer committed this key first, so it's already captured.
Err(fjall::Conflict) => Err(CaptureError::AlreadyExists),
}
})
.await
.expect("output-capture write task panicked")
}
async fn get(&self, id: HistoryId) -> Result<Option<CommandCapture>, GetOutputError> {
let keyspace = self.keyspace.clone();
let key = ActiveSchema::serialize_key(id).expect("history id serialization is infallible");
tokio::task::spawn_blocking(move || {
match keyspace.get(key).map_err(|err| GetOutputError::Storage(Box::new(err)))? {
Some(slice) => {
let capture = ActiveSchema::deserialize_value(slice.to_vec())
.expect("stored value is a valid CommandCapture");
Ok(Some(capture))
}
None => Ok(None),
}
})
.await
.expect("output-capture read task panicked")
}
async fn remove(&self, ids: Vec<HistoryId>) -> Result<(), DeleteOutputError> {
let keys: Vec<_> = ids
.into_iter()
.map(|id| {
ActiveSchema::serialize_key(id).expect("history id serialization is infallible")
})
.collect();
if keys.is_empty() {
return Ok(());View on GitHub (pinned to c0c717ab04)
Solutions
- Ensure the Atuin version reading the data is not older than the version that wrote it
- If corruption is suspected, delete/rebuild the output-capture keyspace from history
- Restore from a consistent backup that includes matching schema versions
- Report a bug if it reproduces on a single unmodified installation
Example fix
// before
.expect("stored value is a valid CommandCapture");
// after
ActiveSchema::deserialize_value(slice.to_vec())
.map_err(|err| GetOutputError::Schema(Box::new(err)))? Defensive patterns
Strategy: fallback
Try / catch
// Treat undecodable values as missing instead of panicking:
let capture = match ActiveSchema::deserialize_value(slice.to_vec()) {
Ok(c) => c,
Err(e) => { tracing::warn!("undecodable capture: {e}"); return Ok(None); }
}; Prevention
- Don't downgrade Atuin across schema versions on the same data directory
- Back up and restore the whole data directory consistently
- Check filesystem health (fsck, SMART) if corruption recurs
- Treat stored blobs as untrusted input and decode fallibly
When it happens
Trigger: Calling `get(id)` for a history id whose stored bytes were written by a different Atuin/fjall schema version, were corrupted on disk, or were truncated by an unclean shutdown.
Common situations: Downgrading Atuin after a schema change; restoring a partial/inconsistent data directory from backup; disk corruption; manually copying keyspace files between machines with different versions.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- output-capture read task panicked
- trailing bytes decoding HistoryRecord::Delete - malformed? g
- trailing bytes in encoded shell alias record. malformed
- too many entries in v0 dotfiles env create record, got {}, e
- trailing bytes in encoded dotfiles env record, malformed
AI-assisted analysis of atuinsh/atuin@c0c717ab04 (2026-09-12).
Data as JSON: /api/errors/3bf7de5c0adb3e77.
Report an issue: GitHub.