clockworklabs/SpacetimeDB · error · std::io::Error
failed to decode commit header field '{field}': {e}
Error message
failed to decode commit header field '{field}': {e} What it means
Defensive decoder error from Header decoding: the fixed header buffer is parsed field-by-field (min_tx_offset u64, epoch u64, n u16, len u32) and a DecodeError from spacetimedb_sats::buffer is wrapped with the failing field's name via decode_header_error. Because the header is read into a stack buffer sized exactly Header::LEN (22 bytes in v1, 14 in v0 - exactly covering the fields), this path cannot fire for on-disk data; it only triggers if the buffer length and the decode sequence disagree, i.e. a crate bug or version skew.
Source
Thrown at crates/commitlog/src/commit.rs:413
let size_in_bytes = Commit::from(commit).encoded_len() as u64;
Self {
tx_range,
size_in_bytes,
epoch,
checksum,
}
}
}
fn decode_u32<R: Read>(mut read: R) -> io::Result<u32> {
let mut buf = [0; 4];
read.read_exact(&mut buf)?;
Ok(u32::from_le_bytes(buf))
}
fn decode_header_error(e: DecodeError, field: &str) -> io::Error {
invalid_data(format!("failed to decode commit header field '{field}': {e}"))
}
fn invalid_data<E>(e: E) -> io::Error
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
io::Error::new(io::ErrorKind::InvalidData, e)
}
#[cfg(test)]
mod tests {
use std::num::NonZeroU8;
use proptest::prelude::*;
use super::*;
use crate::{payload::ArrayDecoder, tests::helpers::enable_logging, DEFAULT_LOG_FORMAT_VERSION};
View on GitHub (pinned to 9e0d92412f)
Solutions
- Align all workspace members and nodes on a single SpacetimeDB/commitlog version and rebuild from clean state.
- Report upstream with the exact field name from the message - it identifies which read overran and pinpoints the layout mismatch.
Defensive patterns
Strategy: try-catch
Try / catch
match reader.next_commit() {
Ok(Some(c)) => commits.push(c),
Ok(None) => {}
Err(e) if e.kind() == io::ErrorKind::InvalidData
&& e.to_string().contains("failed to decode commit header field") =>
{
// layout/version skew inside the crate: unrecoverable - stop and escalate
return Err(e.into());
}
Err(e) => return Err(e.into()),
} Prevention
- Pin a single SpacetimeDB/commitlog version across all workspace members and nodes.
- Never read logs written by a different (especially vendored/patched) commitlog version.
- If this fires, capture the field name from the message - it identifies the layout mismatch for an upstream report.
When it happens
Trigger: Effectively unreachable through public APIs: it would require decoding a header from a buffer shorter than the fields being read, which the fixed-size read_exact makes impossible. Realistic only with a vendored/patched commitlog whose Header::LEN differs from the field sequence, or mixed crate versions writing/reading the log.
Common situations: Mixing commitlog crate versions (forks with a different header layout); otherwise not observed.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to decode commit
- failed to read {} bytes of commit payload: {}
- failed to read checksum: {e}
- a row was a sequence trigger but there was no generated colu
- Error looking up name for truncated table {table_id:?}
AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20).
Data as JSON: /api/errors/91ce31ed46119071.
Report an issue: GitHub.