{"record":{"id":"caddbbae58725ae8","repo":"clockworklabs/SpacetimeDB","slug":"committedstate-replay-table-updated-should-be-e","errorCode":null,"errorMessage":"`CommittedState::replay_table_updated` should be empty at the end of a commit, but found {} entries","messagePattern":"`CommittedState::replay_table_updated` should be empty at the end of a commit, but found (.+?) entries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/datastore/src/locking_tx_datastore/replay.rs","lineNumber":1063,"sourceCode":"        // as if that happens, the database is bricked.\n\n        table.clear(blob_store);\n\n        Ok(())\n    }\n\n    fn replay_end_tx(&mut self) -> Result<()> {\n        self.next_tx_offset += 1;\n\n        if !self.replay_columns_to_ignore.is_empty() {\n            return Err(anyhow::anyhow!(\n                \"`CommittedState::replay_columns_to_ignore` should be empty at the end of a commit, but found {} entries\",\n                self.replay_columns_to_ignore.len(),\n            ).into());\n        }\n\n        if !self.replay_table_updated.is_empty() {\n            return Err(anyhow::anyhow!(\n                \"`CommittedState::replay_table_updated` should be empty at the end of a commit, but found {} entries\",\n                self.replay_table_updated.len(),\n            )\n            .into());\n        }\n\n        // Any dropped tables should be fully gone by the end of a transaction;\n        // if we see any reference to them in the future we should error, not ignore.\n        self.replay_table_dropped.clear();\n\n        Ok(())\n    }\n}\n\npub(super) fn build_sequence_state(datastore: &Locking, cs: &mut CommittedState) -> Result<()> {\n    let sequence_state = cs.build_sequence_state()?;\n    // Reset our sequence state so that they start in the right places.\n    *datastore.sequence_state.lock() = sequence_state;","sourceCodeStart":1045,"sourceCodeEnd":1081,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/datastore/src/locking_tx_datastore/replay.rs#L1045-L1081","documentation":"replay_end_tx requires replay_table_updated to be drained by the end of each committed transaction: entries are added when a new st_table row is seen during replay and removed when the corresponding old st_table row is deleted (visit_delete for ST_TABLE_ID). Non-empty means a table schema update ended without its predecessor being cleaned up, so replay fails rather than continue with ambiguous state.","triggerScenarios":"A schema-change transaction whose st_table delete row is missing from the log (corruption or truncation); reordered system-table writes from a different version; a bug in the add/remove pairing during replay of renames or column additions.","commonSituations":"Crash mid table-rename or column-add commit; version skew between writer and replayer; fuzzed commitlogs.","solutions":["Restore from a snapshot taken before the affected transaction","Replay with the spacetimedb version that wrote the schema change","Report the invariant violation with the commitlog for diagnosis"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch at open, restore from a snapshot taken before the affected transaction, and report the invariant violation with the commitlog for root-causing.","preventionTips":["Snapshot before schema migrations (renames, column adds)","Keep all replaying nodes on the version that wrote the log","Crash-mid-migration should trigger re-snapshot once recovered"],"tags":["rust","spacetimedb","replay","internal-invariant","schema-change"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}