hibernate/hibernate-orm · error · IllegalStateException
getRollbackOnly() called on inactive transaction (in JPA com
Error message
getRollbackOnly() called on inactive transaction (in JPA compliant mode)
What it means
getRollbackOnly() reads the rollback-only flag (status == MARKED_ROLLBACK). JPA defines this accessor only for active transactions, so in JPA-compliance mode (hibernate.jpa.compliance.transaction=true) calling it on an inactive one throws IllegalStateException; native mode simply evaluates getStatus() == MARKED_ROLLBACK, which is false when inactive.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java:218
// This is the JPA-defined version of this operation,
// so we must check that the transaction is active
throw new IllegalStateException( "setRollbackOnly() called on inactive transaction (in JPA compliant mode)" );
}
else {
// JpaCompliance disables the check, so this method
// is equivalent to our native markRollbackOnly()
CORE_LOGGER.setRollbackOnlyCalledOnInactiveTransaction();
}
}
else {
markRollbackOnly();
}
}
@Override
public boolean getRollbackOnly() {
if ( jpaCompliance && !isActive() ) {
throw new IllegalStateException( "getRollbackOnly() called on inactive transaction (in JPA compliant mode)" );
}
else {
return getStatus() == TransactionStatus.MARKED_ROLLBACK;
}
}
protected boolean allowFailedCommitToPhysicallyRollback() {
return false;
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Guard the read: boolean rollbackOnly = tx.isActive() && tx.getRollbackOnly();
- Restrict flag polling to code that provably runs inside the begun transaction
- In native flows, use getStatus() directly and treat non-active statuses as false
Example fix
// before
if (tx.getRollbackOnly()) { // inactive tx, JPA mode -> IllegalStateException
abortPipeline();
}
// after
if (tx.isActive() && tx.getRollbackOnly()) {
abortPipeline();
} Defensive patterns
Strategy: validation
Validate before calling
boolean rollbackOnly = tx.isActive() && tx.getRollbackOnly();
Prevention
- Read getRollbackOnly() only inside code that provably runs in the transaction
- Use getStatus() == MARKED_ROLLBACK directly in native flows
- Keep monitoring/polling code out of transaction boundaries
When it happens
Trigger: tx.getRollbackOnly() polled before begin() or after the transaction completed, in JPA-compliance mode — e.g. monitoring/decision code that checks the flag in a loop that spans the transaction boundary.
Common situations: Polling loops and health checks that query rollback-only state including outside the transaction; orchestration code shared between transactional and non-transactional steps; frameworks inspecting the flag during cleanup.
Related errors
- setRollbackOnly() called on inactive transaction (in JPA com
- rollback() called on inactive transaction (in JPA compliant
- Transaction already active (in JPA compliant mode)
- Transaction was marked for rollback only
- Newer version [" + latestVersion + "] of entity [" + infoStr
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e0e7d59fcb01d6a8.
Report an issue: GitHub.