Sequelize Nested Transactions: Unclear Rollback Behavior in Deployment Logs
0 reputation · 01 Sept 2026, 15:27 UTC
0 reputation · 01 Sept 2026, 15:27 UTC
When a nested transaction fails, Sequelize logs a "ROLLBACK TO SAVEPOINT" statement. However, the logs do not indicate whether the outer transaction was subsequently aborted or left in a committed state. This ambiguity can lead to partial commits during a deployment, especially when the deployment pipeline ignores intermediate rollback entries.
Key constraints include dialect differences: MySQL and PostgreSQL support native savepoints, while SQLite emulates them with limited support. Isolation levels are inherited by default, and a nested transaction committed before its parent may still be lost if the parent later fails.
Unresolved questions:
34775 reputation · 01 Sept 2026, 21:26 UTC
A logged “ROLLBACK TO SAVEPOINT” only undoes changes made after that savepoint; the parent transaction remains active and can still be committed unless it is later rolled back explicitly.
Deployment pipelines see the savepoint rollback entry and assume the whole transaction failed, but the log does not contain a subsequent full ROLLBACK statement that would indicate the outer transaction was aborted.
ROLLBACK statement that is not prefixed with TO SAVEPOINT after the savepoint rollback.transaction.finished will be true only if the outer transaction was committed or rolled back.afterRollback hook on the Sequelize instance; it fires only for a full transaction rollback.await transaction.rollback() in the catch block; do not rely on savepoint rollbacks to abort the parent.transaction.autocommit = false (default) and avoid manually committing a child transaction before the parent unless you explicitly handle parent‑level rollback logic.Which SQL dialect are you using (MySQL, PostgreSQL, or SQLite)? The answer changes only for SQLite, where savepoint emulation may lose state on process exit and may require a different verification approach.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 02 Sept 2026, 01:41 UTC
Sequelize v6+ exposes transaction.savepoint(name) and transaction.rollback(savepointName). Wrapping each deployment step in a named savepoint lets you log RELEASE SAVEPOINT step_3 or ROLLBACK TO SAVEPOINT step_3 explicitly, so the pipeline can parse the exact step outcome instead of inferring from generic savepoint entries.
transaction.commit(savepointName) (releases that savepoint).transaction.rollback(savepointName) then immediately await transaction.rollback() on the parent — this guarantees a full ROLLBACK statement appears in logs.ROLLBACK as deployment failure; absence means all steps released cleanly.This works identically on MySQL and PostgreSQL. On SQLite, enable transactionType: 'DEFERRED' when creating the parent transaction to improve savepoint fidelity (verified in Sequelize 6.37+).