{"record":{"id":"d733671f684bc7de","repo":"clockworklabs/SpacetimeDB","slug":"begin-mutable-transaction-while-one-is-already-act","errorCode":null,"errorMessage":"begin mutable transaction while one is already active","messagePattern":"begin mutable transaction while one is already active","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/dst/src/engine.rs","lineNumber":195,"sourceCode":"\n            tables.push(TableDelta {\n                table,\n                inserts,\n                deletes,\n                truncated: entry.truncated,\n            });\n        }\n\n        tables.sort_by_key(|delta| delta.table);\n        CommitDelta { tables }\n    }\n\n    pub fn execute(&mut self, interaction: &Interaction) -> anyhow::Result<Observation> {\n        tracing::debug!(?interaction, \"executing interaction\");\n\n        let observation = match interaction {\n            Interaction::BeginMutTx => {\n                anyhow::ensure!(\n                    self.active_mut_tx.is_none(),\n                    \"begin mutable transaction while one is already active\"\n                );\n                let db = self\n                    .db\n                    .as_ref()\n                    .ok_or_else(|| anyhow::anyhow!(\"database is not open\"))?;\n                self.active_mut_tx = Some(db.begin_mut_tx(IsolationLevel::Serializable, Workload::Internal));\n                Ok(Observation::BeganMutTx)\n            }\n            Interaction::Insert { table, row } => {\n                let table_id = self.table_ids[*table];\n                let bytes = row_to_bytes(row);\n                let db = self\n                    .db\n                    .as_ref()\n                    .ok_or_else(|| anyhow::anyhow!(\"database is not open\"))?;\n                let tx = self","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/dst/src/engine.rs#L177-L213","documentation":"The dst engine target allows at most one active mutable transaction: execute(Interaction::BeginMutTx) asserts active_mut_tx.is_none(). This error means BeginMutTx was issued while a previous mutable transaction was still open — no CommitTx (or Replay, which implicitly discards the active tx) happened in between.","triggerScenarios":"A generated interaction sequence like BeginMutTx, Insert, BeginMutTx — the workload generator emitted a second begin without an intervening CommitTx. Note Interaction::Replay silently drops the active transaction, so it also resets this state.","commonSituations":"Bugs in DST workload generators (WorkloadGen) or hand-written interaction scripts; state-machine modeling that forgets the tx-open edge.","solutions":["Fix the generator's state machine: only emit BeginMutTx when no transaction is active","Emit CommitTx (or Replay) before the next BeginMutTx","Track active-transaction state in the driver and assert the invariant between steps"],"exampleFix":"// before: two begins, no commit in between\nvec![BeginMutTx, Insert { .. }, BeginMutTx, Delete { .. }, CommitTx]\n\n// after: one transaction at a time\nvec![BeginMutTx, Insert { .. }, CommitTx, BeginMutTx, Delete { .. }, CommitTx]","handlingStrategy":"validation","validationCode":"// Generator-side state check before emitting BeginMutTx\nfn can_begin_mut_tx(tx_active: bool) -> bool {\n    !tx_active\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model the interaction sequence as a state machine (idle -> tx-open -> idle) and generate transitions, not raw op lists","Only emit BeginMutTx from the idle state; require CommitTx or Replay to return to idle","Add assertions in the driver that BeganMutTx observations strictly alternate with Committed/Replayed ones"],"tags":["rust","spacetimedb","dst","testing","transaction","state-machine"],"backgroundTag":"transaction-already-active","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}