stalwartlabs/stalwart · error · DataCorruption
Invalid version
Error message
Invalid version
What it means
deserialize_events reads a binary-encoded event stream and expects the first byte to equal the current VERSION tag. If the stream ends immediately (handled separately) or the version byte differs, the data is treated as corrupt and deserialization bails with StoreEvent::DataCorruption.
Source
Thrown at crates/trc/src/serializers/binary.rs:38
) -> Vec<u8> {
let mut buf = Vec::with_capacity(num_events * 64);
buf.push(VERSION);
leb128_write(&mut buf, num_events as u64);
for event in events {
event.serialize(&mut buf);
}
buf
}
pub fn deserialize_events(bytes: &[u8]) -> crate::Result<Vec<Event<EventDetails>>> {
let mut iter = bytes.iter();
if *iter.next().ok_or_else(|| {
StoreEvent::DataCorruption
.caused_by(crate::location!())
.details("EOF while reading version")
})? != VERSION
{
crate::bail!(
StoreEvent::DataCorruption
.caused_by(crate::location!())
.details("Invalid version")
);
}
let len = leb128_read(&mut iter).ok_or_else(|| {
StoreEvent::DataCorruption
.caused_by(crate::location!())
.details("EOF while size")
})? as usize;
let mut events = Vec::with_capacity(len);
for n in 0..len {
events.push(Event::deserialize(&mut iter).ok_or_else(|| {
StoreEvent::DataCorruption
.caused_by(crate::location!())
.details(format_compact!("Failed to deserialize event {n}"))
})?);
}View on GitHub (pinned to e962003857)
Solutions
- Verify the data source actually contains trc binary-serialized events (not JSON/other logs).
- Check for version mismatch: decode with the same library version that produced the data.
- Restore the affected records/storage from backup if bytes are corrupted.
- Discard/re-serialize incompatible old payloads through a migration path if provided.
Example fix
// before deserialize_events(&migrated_legacy_blob) // after: only feed blobs produced by matching VERSION deserialize_events(&record.payload)
Defensive patterns
Strategy: type-guard
Validate before calling
// before decoding, check the version byte
fn has_valid_version(buf: &[u8]) -> bool { buf.first() == Some(&VERSION) } Type guard
fn is_binary_event(buf: &[u8]) -> bool { buf.first().copied() == Some(crate::serializers::binary::VERSION) } Try / catch
match deserialize_events(&buf) {
Ok(events) => events,
Err(err) => { log::warn!("corrupt event stream: {err}"); Vec::new() },
} Prevention
- Decode telemetry blobs with the same library version that wrote them.
- Persist a format/version header alongside stored event data.
- Never manually edit or truncate binary event records.
- Restore corrupted storage from backups rather than re-parsing.
When it happens
Trigger: Feeding a byte buffer/iterator to deserialize_events whose first byte is not the serializer's VERSION constant — e.g. data written by a different format version, truncated/replaced header, or not binary-serialized data at all.
Common situations: Reading telemetry/event blobs persisted by an older or newer Stalwart release; corrupted storage records; pointing the code at a file/stream that isn't the expected binary format.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/5914e321e0658279.
Report an issue: GitHub.