{"record":{"id":"5914e321e0658279","repo":"stalwartlabs/stalwart","slug":"invalid-version","errorCode":null,"errorMessage":"Invalid version","messagePattern":"Invalid version","errorType":"error_code","errorClass":"DataCorruption","httpStatus":null,"severity":"error","filePath":"crates/trc/src/serializers/binary.rs","lineNumber":38,"sourceCode":") -> Vec<u8> {\n    let mut buf = Vec::with_capacity(num_events * 64);\n    buf.push(VERSION);\n    leb128_write(&mut buf, num_events as u64);\n    for event in events {\n        event.serialize(&mut buf);\n    }\n    buf\n}\n\npub fn deserialize_events(bytes: &[u8]) -> crate::Result<Vec<Event<EventDetails>>> {\n    let mut iter = bytes.iter();\n    if *iter.next().ok_or_else(|| {\n        StoreEvent::DataCorruption\n            .caused_by(crate::location!())\n            .details(\"EOF while reading version\")\n    })? != VERSION\n    {\n        crate::bail!(\n            StoreEvent::DataCorruption\n                .caused_by(crate::location!())\n                .details(\"Invalid version\")\n        );\n    }\n    let len = leb128_read(&mut iter).ok_or_else(|| {\n        StoreEvent::DataCorruption\n            .caused_by(crate::location!())\n            .details(\"EOF while size\")\n    })? as usize;\n    let mut events = Vec::with_capacity(len);\n    for n in 0..len {\n        events.push(Event::deserialize(&mut iter).ok_or_else(|| {\n            StoreEvent::DataCorruption\n                .caused_by(crate::location!())\n                .details(format_compact!(\"Failed to deserialize event {n}\"))\n        })?);\n    }","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/trc/src/serializers/binary.rs#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndeserialize_events(&migrated_legacy_blob)\n// after: only feed blobs produced by matching VERSION\ndeserialize_events(&record.payload)","handlingStrategy":"type-guard","validationCode":"// before decoding, check the version byte\nfn has_valid_version(buf: &[u8]) -> bool { buf.first() == Some(&VERSION) }","typeGuard":"fn is_binary_event(buf: &[u8]) -> bool { buf.first().copied() == Some(crate::serializers::binary::VERSION) }","tryCatchPattern":"match deserialize_events(&buf) {\n    Ok(events) => events,\n    Err(err) => { log::warn!(\"corrupt event stream: {err}\"); Vec::new() },\n}","preventionTips":["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."],"tags":["serialization","data-corruption","versioning"],"backgroundTag":"checksum-mismatch","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}