clockworklabs/SpacetimeDB · error · io::Error

failed to read {} bytes of commit payload: {}

Error message

failed to read {} bytes of commit payload: {}

What it means

After a commit header decodes, the reader must read exactly `hdr.len` bytes of records. Failing to do so — almost always UnexpectedEof because the file ends early — is reported with the expected byte count and the underlying error. This signature means a commit was partially appended (the process or machine died mid-write), so the log is truncated after the previous commit.

Source

Thrown at crates/commitlog/src/commit.rs:314

    /// [`ChecksumMismatch`] is returned.
    pub fn decode<R: Read>(reader: R) -> io::Result<Option<Self>> {
        Self::decode_internal(reader, DEFAULT_LOG_FORMAT_VERSION)
    }

    pub(crate) fn decode_internal<R: Read>(reader: R, log_format_version: u8) -> io::Result<Option<Self>> {
        let mut reader = Crc32cReader::new(reader);

        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,

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Let SpacetimeDB recovery proceed — a torn final commit is truncated away and the committed prefix is exposed
  2. If the host refuses to open, restore the affected segment from backup or snapshot
  3. Fix the root cause: free disk space, avoid killing the host mid-commit, snapshot with the host stopped
Defensive patterns

Strategy: try-catch

Try / catch

match commit.decode(&mut reader) {
    Ok(None) => break,
    Ok(Some(c)) => commits.push(c),
    Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
        // torn final commit: log is truncated; recover at the committed prefix
        tracing::warn!("commitlog truncated mid-payload: {e}");
        break;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Header decoded but the file ends before `hdr.len` record bytes can be read: process killed mid-append, disk-full abort, or a data directory copied while being written.

Common situations: Power loss or SIGKILL during a reducer commit; disk filling up during append; snapshots or rsync of db files while the host runs.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/b25e9c42d3ade0d6. Report an issue: GitHub.