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
- Guard the handler: if (tx.isActive()) { tx.rollback(); }
- Only roll back transactions your code path began; pair every begin() with exactly one commit-or-rollback
- 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
- Wrap rollback in isActive() guards in every catch/finally
- Only roll back transactions your code path began
- Use markRollbackOnly() when you need lenient, native-mode semantics
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
- setRollbackOnly() called on inactive transaction (in JPA com
- getRollbackOnly() called on inactive transaction (in JPA com
- Transaction already active (in JPA compliant mode)
- Cannot roll back transaction in current status [
- Unable to rollback against JDBC Connection
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a935019f65892764.
Report an issue: GitHub.