{"record":{"id":"8f92bf7b0c744d6a","repo":"clockworklabs/SpacetimeDB","slug":"mismatch-key-in-index-offset-file-expected-act","errorCode":null,"errorMessage":"mismatch key in index offset file: expected={} actual={}","messagePattern":"mismatch key in index offset file: expected=(.+?) actual=(.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/commitlog/src/segment.rs","lineNumber":766,"sourceCode":"        ))\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;\n    use pretty_assertions::assert_matches;\n    use spacetimedb_paths::server::CommitLogDir;\n    use tempfile::tempdir;","sourceCodeStart":748,"sourceCodeEnd":784,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/commitlog/src/segment.rs#L748-L784","documentation":"Same validation pass in validate_commit_at_offset: a commit decoded successfully at the index-recorded byte offset, but its first transaction offset (commit.tx_range.start) differs from the tx_offset key the index claims lives there. The offset index and the segment file disagree about which transaction is stored at that position - a stale or out-of-sync index.","triggerScenarios":"Index entries surviving from a previous incarnation of a segment with the same offset (segment recreated after deletion while the old index was kept); a crash between segment rotation and index flush; manually editing, truncating, or copying index files independently of their segment.","commonSituations":"Re-bootstrapping a follower into a dirty data directory; restoring segment files from backup but not the indexes (or vice versa); two writers having used the same commitlog repo at different times.","solutions":["Delete the stale offset index for the offending segment so it is regenerated from segment contents.","If both segment and index are suspect, remove the pair and re-replicate that range from a leader or snapshot.","Restore the commitlog directory as a whole from a consistent backup.","Ensure only one process ever writes a given commitlog repo."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before repair/verify, scan the segment sequentially and rebuild the expected\n// (tx_offset -> byte_offset) map; compare against the on-disk index and rebuild it\n// on any divergence rather than trusting stale entries.","typeGuard":null,"tryCatchPattern":"match validate_result {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains(\"mismatch key in index offset file\") => {\n        // Stale index: delete and regenerate the offset index, then retry verification.\n    }\n    other => other,\n}","preventionTips":["Treat offset indexes as derived data tied to their segment; never copy one without the other.","Use a single writer per commitlog repository.","After a crash, run the repo's consistency check before resuming replication."],"tags":["commitlog","index","corruption","segment","rust"],"backgroundTag":"index-segment-mismatch","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}