{"record":{"id":"bd2bb954a9f4a093","repo":"SeaQL/sea-orm","slug":"there-is-no-open-transaction-to-rollback-bd2bb9","errorCode":null,"errorMessage":"There is no open transaction to rollback","messagePattern":"There is no open transaction to rollback","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/database/mock.rs","lineNumber":210,"sourceCode":"                        self.transaction_log.push(transaction.into_transaction());\n                    }\n                }\n            }\n            None => panic!(\"There is no open transaction to commit\"),\n        }\n    }\n\n    #[instrument(level = \"trace\")]\n    fn rollback(&mut self) {\n        match self.transaction.as_mut() {\n            Some(transaction) => {\n                if transaction.rollback(self.db_backend) {\n                    if let Some(transaction) = self.transaction.take() {\n                        self.transaction_log.push(transaction.into_transaction());\n                    }\n                }\n            }\n            None => panic!(\"There is no open transaction to rollback\"),\n        }\n    }\n\n    fn drain_transaction_log(&mut self) -> Vec<Transaction> {\n        std::mem::take(&mut self.transaction_log)\n    }\n\n    fn get_database_backend(&self) -> DbBackend {\n        self.db_backend\n    }\n\n    fn ping(&self) -> Result<(), DbErr> {\n        Ok(())\n    }\n}\n\nimpl MockRow {\n    /// Get a value from the [MockRow]","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/SeaQL/sea-orm/blob/e29bcd1b417c41a553b386fe94511d7c64a1c8ec/src/database/mock.rs#L192-L228","documentation":"Mirror of the commit panic: the mock database panics in `rollback` when there is no open transaction (`self.transaction` is `None`). A ROLLBACK without a prior BEGIN, or a second rollback after the transaction already ended, violates the mock's transaction protocol.","triggerScenarios":"Executing `ROLLBACK` on a `MockDatabase` with no active transaction — no `begin` was issued, or the transaction was already committed or rolled back.","commonSituations":"Error-handling paths in tests that always call rollback even when begin never ran; a catch/cleanup handler rolling back twice; test scripts with unmatched BEGIN/ROLLBACK pairs.","solutions":["Only issue ROLLBACK after a successful BEGIN; pair them in the same code path.","Make cleanup idempotent: track whether a transaction is open before rolling back.","Fix double-rollback in error handlers (e.g. rollback in both inner and outer error paths).","Reorder the mock test script so begin precedes rollback."],"exampleFix":"// before\nif err {\n    rollback(stmt) // panics if begin never ran\n}\n\n// after\nbegin(stmt);\nif err {\n    rollback(stmt); // matched pair\n}","handlingStrategy":"validation","validationCode":"// only rollback when a transaction is open\nif tx_open {\n    rollback(stmt);\n    tx_open = false;\n}","typeGuard":"fn can_rollback(mock: &MockDatabase) -> bool {\n    mock.transaction_depth() > 0\n}","tryCatchPattern":"std::panic::catch_unwind(|| mock.rollback()) // prefer fixing the script over catching","preventionTips":["Track transaction state explicitly and only rollback when open.","Avoid rolling back in multiple nested error handlers.","Use RAII guards that rollback at most once.","Keep mock scripts linear and pair every BEGIN with exactly one terminator."],"tags":["panic","transaction","mock","testing"],"backgroundTag":"invalid-state-transition","analyzedSha":"e29bcd1b417c41a553b386fe94511d7c64a1c8ec","analyzedAt":"2026-09-10T11:31:52.468Z","contentChangedAt":"2026-09-10T11:31:52.468Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}