clockworklabs/SpacetimeDB · error · std::io::Error
failed to read checksum
Error message
failed to read checksum: {e} What it means
Raised at the last step of Commit::decode: after the record payload, every commit stores a 4-byte little-endian CRC32C checksum, and reading those bytes failed (kind preserved). Because the checksum is the final thing written for a commit, this almost always means the log ends in the middle of a commit - the header and payload landed but the checksum did not.
Solutions
- Rely on the node's truncation-on-recovery to drop the incomplete commit; restart the node cleanly.
- If it persists, truncate the segment to the last valid commit and restart.
- Ensure backups copy segment files only while the node is stopped, and no external process truncates the data directory.
Defensive patterns
Strategy: try-catch
Try / catch
match reader.next_commit() {
Ok(Some(commit)) => commits.push(commit),
Ok(None) => {}
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
// checksum bytes missing: torn final commit - accept the prefix and stop
}
Err(e) => return Err(e.into()),
} Prevention
- Take backups of the data directory only while the node is stopped, so segments are never copied mid-commit.
- Ensure durable writes (fsync) and healthy disks so commit checksums always land.
- On recovery, accept the last complete commit and let the node truncate the torn tail.
When it happens
Trigger: A commit whose header and payload decoded fine but whose trailing 4 checksum bytes are missing because the write was interrupted (crash/power loss), or the segment file was externally truncated or partially copied.
Common situations: Same torn-write scenarios as the payload-read error, one step later; also seen when backups copy a segment while it is being written.
Related errors
- failed to read bytes of commit payload
- all-zeroes commit header
- repo : first commit in the most recent segment is corrupt
- repo : too many empty segments
- allocation size overflow
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/d943a6722691a863.
Report an issue: GitHub.
Appendix: source
Thrown at crates/commitlog/src/commit.rs:322
let v = if log_format_version == 0 {
Version::V0
} else {
Version::V1
};
let Some(hdr) = Header::decode_internal(&mut reader, v)? else {
return Ok(None);
};
let mut records = vec![0; hdr.len as usize];
reader.read_exact(&mut records).map_err(|e| {
io::Error::new(
e.kind(),
format!("failed to read {} bytes of commit payload: {}", hdr.len, e),
)
})?;
let chk = reader.crc32c();
let crc = decode_u32(reader.into_inner())
.map_err(|e| io::Error::new(e.kind(), format!("failed to read checksum: {e}")))?;
if chk != crc {
return Err(invalid_data(ChecksumMismatch));
}
Ok(Some(Self {
min_tx_offset: hdr.min_tx_offset,
epoch: hdr.epoch,
n: hdr.n,
records,
checksum: crc,
}))
}
/// Convert `self` into an iterator yielding [`Transaction`]s.
///
/// The supplied [`Decoder`] is responsible for extracting individual
/// transactions from the `records` buffer.View on GitHub (pinned to 6dee26c6ef)