hibernate/hibernate-orm · error · IllegalStateException

rollback() called on inactive transaction (in JPA compliant

Error message

rollback() called on inactive transaction (in JPA compliant mode)

What it means

TransactionImpl.rollback() starts with a JPA-compliance check: in JPA-compliant mode (hibernate.jpa.compliance.transaction=true), rolling back an inactive transaction is a spec violation and throws IllegalStateException. Native mode only logs rollbackCalledOnInactiveTransaction; in both modes rollback() on an already completed transaction (ROLLED_BACK/NOT_ACTIVE) is an allowed no-op.

Source

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

			}
		}
	}

	@Nonnull
	public TransactionDriver internalGetTransactionDriverControl() {
		// NOTE here to help be a more descriptive NullPointerException
		if ( transactionDriverControl == null ) {
			throw new IllegalStateException( "Transaction was not properly begun/started" );
		}
		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() {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Guard the handler: if (tx.isActive()) { tx.rollback(); }
  2. Only roll back transactions your code path began; pair every begin() with exactly one commit-or-rollback
  3. For lenient native semantics use markRollbackOnly(), which tolerates inactive transactions

Example fix

// before
try {
    doWork();
    tx.commit();
} catch (RuntimeException e) {
    tx.rollback(); // tx never begun or already done -> IllegalStateException in JPA mode
}

// after
try {
    doWork();
    tx.commit();
} catch (RuntimeException e) {
    if (tx.isActive()) {
        tx.rollback();
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (tx.isActive()) {
    tx.rollback();
}

Prevention

When it happens

Trigger: em.getTransaction().rollback() in a catch/finally block when the transaction was never begun or already completed, while the factory runs with JPA transaction compliance enabled.

Common situations: A catch-all rollback handler that runs even when begin() failed earlier; rollback attempted after commit() already finished; shared error-handling helpers applied to code paths that do not always start a transaction.

Related errors


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