risingwavelabs/risingwave · error · BackupError
metadata snapshot is truncated while reading u32
Error message
metadata snapshot is truncated while reading u32
What it means
read_u32_le is a cursor helper used when parsing metadata snapshot sections; it throws BackupError::Other when fewer than 4 bytes remain in the in-memory buffer, reporting "metadata snapshot is truncated while reading u32". It means a length/count field was expected but the section data ran out mid-parse.
Solutions
- Validate the snapshot object size against the backup manifest and restore from an intact backup.
- Check that the parser's expected section layout matches the snapshot's format_version.
- Re-run the restore and check object store read errors/short reads in logs before concluding corruption.
- In tests, build payloads via the writer helpers so all u32 length prefixes are emitted.
Example fix
// before: decoding a manually built buffer missing a length prefix let m = decode_section(&mut &payload[10..])?; // short slice // after: guarantee the full section is buffered ensure!(payload.len() >= section_len, "section truncated"); let m = decode_section(&mut &payload[10..])?;
Defensive patterns
Strategy: validation
Validate before calling
// before calling section decoders, ensure the buffer holds the whole section
if buf.len() < expected_section_len {
return Err(anyhow!("section buffer truncated: {} < {}", buf.len(), expected_section_len));
} Type guard
fn has_u32(buf: &[u8]) -> bool { buf.len() >= 4 } Try / catch
match read_u32_le(&mut buf) {
Ok(v) => v,
Err(e) if e.to_string().contains("truncated while reading u32") => {
return Err(anyhow!("snapshot section truncated; restore from intact backup"));
}
Err(e) => return Err(e.into()),
} Prevention
- Buffer entire snapshot bytes before parsing sections; avoid partial reads.
- Validate snapshot size against the backup manifest first.
- Use writer helpers to generate test fixtures so every u32 prefix is present.
When it happens
Trigger: Calling decode functions (e.g. decode_prost_message, section list decoders in meta_snapshot_v2) with a buffer cut off before a u32 length prefix — truncated section payload, a hand-crafted or corrupted snapshot body, or reading a slice boundary incorrectly.
Common situations: Restoring a snapshot whose object storage read truncated the buffer; tests feeding partial section bytes; corrupted backup files; mixing snapshot versions where a section is shorter than the parser expects.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- meta snapshot is missing checksum
- prost payload length
- unexpected EOF while decoding meta snapshot
- BackupStorage error
- Checksum mismatch: expected
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/2862d4db1cdfb1f6.
Report an issue: GitHub.
Appendix: source
Thrown at src/storage/backup/src/meta_snapshot.rs:258
}
fn verify_checksum(&self, checksum: &[u8]) -> BackupResult<()> {
Self::verify_checksum_with_hasher(&self.hasher, checksum)
}
fn verify_checksum_with_hasher(hasher: &XxHash64, checksum: &[u8]) -> BackupResult<()> {
let expected = u64::from_le_bytes(checksum.try_into().expect("u64 length"));
let found = hasher.finish();
if expected != found {
return Err(BackupError::ChecksumMismatch { expected, found });
}
Ok(())
}
}
pub(crate) fn read_u32_le(buf: &mut &[u8]) -> BackupResult<u32> {
if buf.remaining() < 4 {
return Err(BackupError::Other(anyhow::anyhow!(
"metadata snapshot is truncated while reading u32"
)));
}
Ok(buf.get_u32_le())
}
impl<T: Metadata> Display for MetaSnapshot<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "format_version: {}", self.format_version)?;
writeln!(f, "id: {}", self.id)?;
writeln!(f, "{}", self.metadata)?;
Ok(())
}
}
View on GitHub (pinned to 6469eb736d)