{"record":{"id":"62e5f3173e43b594","repo":"clockworklabs/SpacetimeDB","slug":"failed-to-decode-commit","errorCode":null,"errorMessage":"failed to decode commit","messagePattern":"failed to decode commit","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/commitlog/src/segment.rs","lineNumber":772,"sourceCode":"        Err(io::Error::new(\n            ErrorKind::InvalidData,\n            format!(\"No valid commit found in index up to key: {candidate_last_key}\"),\n        ))\n    }\n\n    /// Validates and decodes a commit at `byte_offset` in the segment.\n    ///\n    /// # Returns\n    /// * `Ok(commit::Metadata)` - If a valid commit is found with matching transaction offset\n    /// * `Err` - If commit can't be decoded or has mismatched transaction offset\n    fn validate_commit_at_offset<R: io::Read + io::Seek>(\n        reader: &mut R,\n        tx_offset: TxOffset,\n        byte_offset: u64,\n    ) -> io::Result<commit::Metadata> {\n        reader.seek(SeekFrom::Start(byte_offset))?;\n        let commit = commit::Metadata::extract(reader)?\n            .ok_or_else(|| io::Error::new(ErrorKind::InvalidData, \"failed to decode commit\"))?;\n\n        if commit.tx_range.start != tx_offset {\n            return Err(io::Error::new(\n                ErrorKind::InvalidData,\n                format!(\n                    \"mismatch key in index offset file: expected={} actual={}\",\n                    tx_offset, commit.tx_range.start\n                ),\n            ));\n        }\n\n        Ok(commit)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use itertools::Itertools;","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/3653d2ed498fddbd83b7062aa6bf8970e18635ec/crates/commitlog/src/segment.rs#L754-L790","documentation":"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.","triggerScenarios":"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.","commonSituations":"The same crash/async-fsync class as the other index validation errors: unclean shutdown, partial restore, or externally truncated segments.","solutions":["Rebuild the offset index from segment data","Trim trailing invalid data before rebuilding so the new index never points into the tail","Fall back to sequential scan reads when this error is detected","Pair index and segment files when restoring from backups"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"fn is_commit_decode_failed(err: &io::Error) -> bool {\n    err.kind() == io::ErrorKind::InvalidData && err.to_string().contains(\"failed to decode commit\")\n}","tryCatchPattern":"match validate_commit_at_offset(&mut reader, tx_offset, byte_offset) {\n    Ok(meta) => Ok(meta),\n    Err(e) if is_commit_decode_failed(&e) => {\n        // indexed position is unusable; fall back to sequential scan\n        scan_for_tx(&mut reader, tx_offset)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Rebuild offset indexes after crashes instead of reusing them","Treat decode failure at an indexed offset as index distrust, not data loss, until a scan confirms","Keep index writes ordered after the data they describe"],"tags":["rust","commitlog","offset-index","decode","invalid-data"],"backgroundTag":"index-corruption","analyzedSha":"3653d2ed498fddbd83b7062aa6bf8970e18635ec","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}