{"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":775,"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":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/3653d2ed498fddbd83b7062aa6bf8970e18635ec/crates/commitlog/src/segment.rs#L757-L793","documentation":"validate_commit_at_offset successfully decodes a commit header at the index's byte offset, but its tx_range.start differs from the tx_offset key stored in the index. The entry maps a transaction offset to the wrong byte position, returning io::ErrorKind::InvalidData with expected/actual values. This is the detectable form of a stale offset index after a crash or partial restore.","triggerScenarios":"Index entry not yet updated after commits were rewritten at new byte positions (async index fsync plus crash); segment and index from different backup generations; concurrent external modification of segment files.","commonSituations":"Unclean shutdown between segment write and index flush; restoring a segment file but keeping the old index; copying logs between nodes with mismatched index state.","solutions":["Rebuild the offset index by deleting index files and reopening the log","Restore segment and index files only as matched pairs from the same snapshot","Handle the error by falling back to a linear scan for the requested offset","Log expected vs actual offsets to confirm which direction the index is stale"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"fn is_index_offset_mismatch(err: &io::Error) -> bool {\n    err.kind() == io::ErrorKind::InvalidData && err.to_string().contains(\"mismatch key in index offset file\")\n}","tryCatchPattern":"match validate_commit_at_offset(&mut reader, tx_offset, byte_offset) {\n    Ok(meta) => Ok(meta),\n    Err(e) if is_index_offset_mismatch(&e) => {\n        // entry maps to the wrong byte position: scan from the previous valid entry\n        scan_for_tx(&mut reader, tx_offset)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Restore index and segment files only from the same snapshot","Log expected vs actual tx offsets when validation fails to measure index staleness","Rebuild indexes rather than patching individual entries"],"tags":["rust","commitlog","offset-index","mismatch","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"}