hibernate/hibernate-orm · error · TransactionException

Cannot roll back transaction in current status [

Error message

Cannot roll back transaction in current status [

What it means

rollback() no-ops only for ROLLED_BACK and NOT_ACTIVE; for everything else it checks TransactionStatus.canRollback(), which is true only for ACTIVE, MARKED_ROLLBACK, and FAILED_COMMIT. Statuses such as COMMITTED, COMMITTING, or ROLLING_BACK cannot be rolled back, so a TransactionException names the offending status.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java:124

		}
		else {
			return transactionDriverControl;
		}
	}

	@Override
	public void rollback() {
		if ( !isActive() && jpaCompliance ) {
			throw new IllegalStateException( "rollback() called on inactive transaction (in JPA compliant mode)" );
		}

		final var status = getStatus();
		if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
			// allow rollback() on completed transaction as noop
			CORE_LOGGER.rollbackCalledOnInactiveTransaction();
		}
		else if ( !status.canRollback() ) {
			throw new TransactionException( "Cannot roll back transaction in current status [" + status.name() + "]" );
		}
		else if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {
			CORE_LOGGER.rollingBackTransaction();
			internalGetTransactionDriverControl().rollback();
		}
	}

	@Override
	public boolean isActive() {
		if ( transactionDriverControl == null ) {
			if ( session.isOpen() ) {
				transactionDriverControl =
						transactionCoordinator.getTransactionDriverControl();
			}
			else {
				return false;
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check the status before rolling back: if (tx.getStatus().canRollback()) tx.rollback();
  2. Do not touch the transaction after commit() returns — start a new transaction if compensating work is needed
  3. Order cleanup logic so commit is the final step and later failures cannot reach the transaction object

Example fix

// before
try {
    tx.commit();
    notifyListeners();
} catch (RuntimeException e) {
    tx.rollback(); // status COMMITTED -> TransactionException
}

// after
try {
    tx.commit();
} catch (RuntimeException e) {
    if (tx.getStatus().canRollback()) {
        tx.rollback();
    }
    throw e;
}
notifyListeners();
Defensive patterns

Strategy: validation

Validate before calling

org.hibernate.resource.transaction.spi.TransactionStatus st = tx.getStatus();
if (st == org.hibernate.resource.transaction.spi.TransactionStatus.ROLLED_BACK
        || st == org.hibernate.resource.transaction.spi.TransactionStatus.NOT_ACTIVE) {
    // Hibernate no-ops these; nothing to do
} else if (st.canRollback()) {
    tx.rollback();
} else {
    log.warn("Cannot roll back transaction in status {}", st);
}

Try / catch

try {
    tx.rollback();
} catch (TransactionException e) {
    if (String.valueOf(e.getMessage()).startsWith("Cannot roll back transaction")) {
        // commit already finished or is in flight — nothing to undo
        log.warn("Rollback skipped: {}", e.getMessage());
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: tx.rollback() after tx.commit() succeeded (status COMMITTED); rollback attempted while a commit is in progress (COMMITTING) or while another rollback is already running (ROLLING_BACK); synchronization callbacks trying to roll back mid-commit.

Common situations: Catch blocks that run after a successful commit and roll back 'to be safe'; post-commit listeners throwing exceptions that trigger a generic rollback path; concurrent error handling around a completing transaction.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/c2b9532924b904fa. Report an issue: GitHub.