SeaQL/sea-orm · error
There is uncommitted nested transaction
Error message
There is uncommitted nested transaction
What it means
into_transaction() converts the accumulated mock statement buffer into a Transaction. It panics when transaction_depth != 0, meaning BEGIN/COMMIT pairs inside the buffered statements are unbalanced — the transaction was never fully committed (or rolled back), so the statement set is not a complete transaction.
Source
Thrown at sea-orm-sync/src/database/mock.rs:434
true
} else {
self.push(Statement::from_string(
db_backend,
format!("ROLLBACK TO SAVEPOINT savepoint_{}", self.transaction_depth),
));
self.transaction_depth -= 1;
false
}
}
fn push(&mut self, stmt: Statement) {
self.stmts.push(stmt);
}
fn into_transaction(self) -> Transaction {
match self.transaction_depth {
0 => Transaction { stmts: self.stmts },
_ => panic!("There is uncommitted nested transaction"),
}
}
}
#[cfg(test)]
#[cfg(feature = "mock")]
mod tests {
#[cfg(feature = "sync")]
use crate::util::StreamShim;
use crate::{
DbBackend, DbErr, IntoMockRow, MockDatabase, Statement, Transaction, TransactionError,
TransactionTrait, entity::*, error::*, tests_cfg::*,
};
// In the sync variant `StreamShim` provides `try_next`; `futures_util` isn't a dependency there.
#[cfg(not(feature = "sync"))]
use futures_util::TryStreamExt;
use pretty_assertions::assert_eq;
View on GitHub (pinned to e29bcd1b41)
Solutions
- Balance every begin() with a commit() or rollback() before draining the transaction log
- Check nested-transaction depth handling in the code under test (savepoints must be committed in order)
- Move the into_transaction()/log assertion after all transaction operations complete
Example fix
// before conn.begin(); conn.execute(stmt).unwrap(); let log = db.into_transaction_log(); // panics: nested txn open // after conn.begin(); conn.execute(stmt).unwrap(); conn.commit(); let log = db.into_transaction_log(); // ok
Defensive patterns
Strategy: validation
Validate before calling
// before draining the log, ensure all nested transactions are closed: conn.commit(); // closes the last open savepoint/transaction let log = mock_db.into_transaction_log();
Try / catch
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| txn.into_transaction()))
.map_err(|_| anyhow!("uncommitted nested transaction before drain"))?; Prevention
- Balance every begin/commit pair, including savepoints in nested-transaction code
- Assert on the transaction log only after all operations (and their commits) complete
- Review error paths that bail out mid-transaction and add rollback handling
When it happens
Trigger: Draining the mock transaction log / calling into_transaction() while nested (savepoint) transactions are still open: a begin() without a matching commit(), or extra begins over commits.
Common situations: Application code opening nested transactions it never commits; test assertions run before the final commit; savepoint depth mismatch after an error path skipped a commit.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- There is uncommitted nested transaction
- There is no open transaction to commit
- There is no open transaction to rollback
- There is no open transaction to commit
- There is no open transaction to rollback
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/3c739b6e4f9fc56f.
Report an issue: GitHub.