clockworklabs/SpacetimeDB · error · io::Error

failed to decode commit

Error message

failed to decode commit

What it means

validate_commit_at_offset seeks to the byte offset supplied by the offset index and calls commit::Metadata::extract; if it returns None (no readable bytes at that position), the error io::ErrorKind::InvalidData 'failed to decode commit' is raised. Like its siblings, it means the index pointed somewhere without a full commit.

Solutions

  1. Rebuild the offset index from segment data
  2. Trim trailing invalid data before rebuilding so the new index never points into the tail
  3. Fall back to sequential scan reads when this error is detected
  4. Pair index and segment files when restoring from backups
Defensive patterns

Strategy: fallback

Type guard

fn is_commit_decode_failed(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::InvalidData && err.to_string().contains("failed to decode commit")
}

Try / catch

match validate_commit_at_offset(&mut reader, tx_offset, byte_offset) {
    Ok(meta) => Ok(meta),
    Err(e) if is_commit_decode_failed(&e) => {
        // indexed position is unusable; fall back to sequential scan
        scan_for_tx(&mut reader, tx_offset)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Index byte offset beyond the valid data region (EOF or preallocated tail); segment truncated after the index was built; byte offset zero/garbage from a corrupt index record.

Common situations: The same crash/async-fsync class as the other index validation errors: unclean shutdown, partial restore, or externally truncated segments.

Understand the failure class

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-08-20). Data as JSON: /api/errors/62e5f3173e43b594. Report an issue: GitHub.

Appendix: source

Thrown at crates/commitlog/src/segment.rs:772

        Err(io::Error::new(
            ErrorKind::InvalidData,
            format!("No valid commit found in index up to key: {candidate_last_key}"),
        ))
    }

    /// Validates and decodes a commit at `byte_offset` in the segment.
    ///
    /// # Returns
    /// * `Ok(commit::Metadata)` - If a valid commit is found with matching transaction offset
    /// * `Err` - If commit can't be decoded or has mismatched transaction offset
    fn validate_commit_at_offset<R: io::Read + io::Seek>(
        reader: &mut R,
        tx_offset: TxOffset,
        byte_offset: u64,
    ) -> io::Result<commit::Metadata> {
        reader.seek(SeekFrom::Start(byte_offset))?;
        let commit = commit::Metadata::extract(reader)?
            .ok_or_else(|| io::Error::new(ErrorKind::InvalidData, "failed to decode commit"))?;

        if commit.tx_range.start != tx_offset {
            return Err(io::Error::new(
                ErrorKind::InvalidData,
                format!(
                    "mismatch key in index offset file: expected={} actual={}",
                    tx_offset, commit.tx_range.start
                ),
            ));
        }

        Ok(commit)
    }
}

#[cfg(test)]
mod tests {
    use itertools::Itertools;

View on GitHub (pinned to 3653d2ed49)