{"record":{"id":"3fba1de60f65abe0","repo":"SeaQL/sea-orm","slug":"fail-to-rollback-transaction-3fba1d","errorCode":null,"errorMessage":"Fail to rollback transaction","messagePattern":"Fail to rollback transaction","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/database/transaction.rs","lineNumber":404,"sourceCode":"        }\n        Ok(())\n    }\n}\n\n#[async_trait::async_trait]\nimpl TransactionSession for DatabaseTransaction {\n    async fn commit(self) -> Result<(), DbErr> {\n        self.commit().await\n    }\n\n    async fn rollback(self) -> Result<(), DbErr> {\n        self.rollback().await\n    }\n}\n\nimpl Drop for DatabaseTransaction {\n    fn drop(&mut self) {\n        self.start_rollback().expect(\"Fail to rollback transaction\");\n    }\n}\n\n#[async_trait::async_trait]\nimpl ConnectionTrait for DatabaseTransaction {\n    fn get_database_backend(&self) -> DbBackend {\n        // this way we don't need to lock just to know the backend\n        self.backend\n    }\n\n    #[instrument(level = \"trace\", skip(stmt))]\n    #[allow(unused_variables)]\n    async fn execute_raw(&self, stmt: Statement) -> Result<ExecResult, DbErr> {\n        debug_print!(\"{}\", stmt);\n\n        super::tracing_spans::with_db_span!(\n            \"sea_orm.execute\",\n            self.backend,","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/SeaQL/sea-orm/blob/e29bcd1b417c41a553b386fe94511d7c64a1c8ec/src/database/transaction.rs#L386-L422","documentation":"When a DatabaseTransaction is dropped without commit or explicit rollback, Drop calls start_rollback() and panics if rollback cannot be scheduled. This guarantees transactions are never silently leaked, but it turns an inability to roll back (e.g. connection already closed or the async runtime is shutting down) into a panic during unwinding/drop.","triggerScenarios":"Dropping a DatabaseTransaction whose backing connection is broken, whose rollback future could not be spawned on the runtime, or dropping during process/runtime shutdown; also double-drop or drop after the connection was consumed elsewhere.","commonSituations":"Using ? to exit a scope without explicit rollback while the pool/connection is dead; tearing down a tokio runtime while transactions are still in scope; panics inside a transaction body causing drop-during-unwind.","solutions":["Always commit or roll back transactions explicitly instead of relying on Drop.","Ensure the async runtime outlives all open transactions; do not drop transactions during runtime shutdown.","Verify the connection is still alive (ping) before starting work that may end in an implicit rollback.","If you must drop mid-failure, call .rollback().await yourself and handle its Result."],"exampleFix":"// before\nlet txn = db.begin().await?;\ndo_work(&txn).await?;\n// drop(txn) may panic on failed implicit rollback\n// after\nlet txn = db.begin().await?;\nmatch do_work(&txn).await {\n    Ok(v) => txn.commit().await?,\n    Err(e) => { txn.rollback().await.ok(); return Err(e); }\n}","handlingStrategy":"try-catch","validationCode":"// Before relying on drop-rollback, ensure the connection is usable:\nlet alive = txn.get_database_backend().ping().is_ok(); // schedule explicit rollback if false","typeGuard":"fn txn_alive(txn: &DatabaseTransaction) -> bool { matches!(txn.ping().await, Ok(())) }","tryCatchPattern":"// Panics in Drop cannot be caught at the drop site; prevent instead:\nlet res = scopeguard::guard((), |_| {});\nmatch body(&txn).await {\n    Ok(v) => { txn.commit().await?; Ok(v) }\n    Err(e) => { txn.rollback().await.ok(); Err(e) } // explicit, non-panicking rollback\n}","preventionTips":["Always call commit() or rollback() explicitly; never rely on Drop","Keep transactions inside a scope that outlives the async runtime","Ping the connection before long transactional work","In tests, avoid runtime teardown while transactions are in scope"],"tags":["panic","transaction","rollback","drop"],"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"}