quickwit-oss/quickwit · error · io::Error (InvalidData)
invalid split recovery metadata magic number
Error message
invalid split recovery metadata magic number
What it means
`SplitRecoveryMetadata::deserialize` expects a byte blob starting with a fixed magic header (SPLIT_RECOVERY_METADATA_MAGIC) of at least header length. If the bytes are too short or the magic does not match, the data is not split recovery metadata in the expected envelope format, so it fails with InvalidData.
Source
Thrown at quickwit/quickwit-proto/src/metastore/mod.rs:62
use prost::Message;
let mut output =
Vec::with_capacity(SPLIT_RECOVERY_METADATA_HEADER_LEN + self.encoded_len());
output.extend_from_slice(SPLIT_RECOVERY_METADATA_MAGIC);
output.push(SPLIT_RECOVERY_METADATA_FORMAT_VERSION);
self.encode(&mut output)
.expect("encoding a protobuf into a Vec should not fail");
output
}
/// Deserializes split recovery metadata embedded in a split bundle.
pub fn deserialize(mut bytes: &[u8]) -> io::Result<Self> {
use prost::Message;
if bytes.len() < SPLIT_RECOVERY_METADATA_HEADER_LEN
|| &bytes[..SPLIT_RECOVERY_METADATA_MAGIC.len()] != SPLIT_RECOVERY_METADATA_MAGIC
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"invalid split recovery metadata magic number",
));
}
let version = bytes[SPLIT_RECOVERY_METADATA_MAGIC.len()];
if version != SPLIT_RECOVERY_METADATA_FORMAT_VERSION {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("unsupported split recovery metadata format version: {version}"),
));
}
bytes = &bytes[SPLIT_RECOVERY_METADATA_HEADER_LEN..];
Self::decode(bytes).map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
}
}
#[cfg(test)]
mod split_recovery_metadata_tests {View on GitHub (pinned to a39730c5cd)
Solutions
- Confirm the bytes being passed actually come from SplitRecoveryMetadata::serialize.
- Delete or re-generate stale recovery metadata written by an older Quickwit version.
- Check the code path that produced the blob for offset/concatenation mistakes.
- Use matching Quickwit versions across the cluster so all nodes write the same envelope format.
Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_recovery_metadata(bytes: &[u8]) -> bool {
bytes.len() > 5 && &bytes[..5] == b"QWSRM" // header length >= magic len
} Try / catch
match SplitRecoveryMetadata::deserialize(&bytes) {
Ok(meta) => handle(meta),
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
// legacy or foreign payload: regenerate or discard
log::warn!("bad recovery metadata envelope: {e}");
}
Err(e) => return Err(e.into()),
} Prevention
- Only deserialize blobs produced by SplitRecoveryMetadata::serialize from the same Quickwit version.
- Clean up legacy metadata left by older releases before upgrading.
- Avoid hand-editing or truncating serialized metadata files.
When it happens
Trigger: Calling SplitRecoveryMetadata::deserialize on bytes produced by an older format (no magic header), on entirely unrelated bytes, or on a file read at the wrong offset.
Common situations: Upgrading Quickwit over a metastore/object store that still holds pre-magic-format blobs; hand-editing or truncating recovery metadata files; deserializing the wrong payload from a queue or file.
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.
Related errors
- unsupported split recovery metadata format version: {version
- dynamic protobuf decode error wrapped as io::Error (InvalidD
- unsupported split recovery metadata format version: {version
- unsupported split fields format version: {version_byte[0]}
- `doc_batch` should not be empty
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/f51803008d3452ea.
Report an issue: GitHub.