hibernate/hibernate-orm · error · IllegalStateException

setRollbackOnly() called on inactive transaction (in JPA com

Error message

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

What it means

setRollbackOnly() is the JPA-defined way to mark a transaction rollback-only, and JPA requires an active transaction. In JPA-compliance mode TransactionImpl throws IllegalStateException when the transaction is inactive; in native mode it just logs setRollbackOnlyCalledOnInactiveTransaction and continues (equivalent to the lenient markRollbackOnly()).

Source

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

	@Override
	public void markRollbackOnly() {
		// This is the Hibernate-specific API, whereas setRollbackOnly is the
		// JPA-defined API. In our opinion, it's much more user-friendly to
		// always allow the client to indicate that the transaction should
		// not be allowed to commit.
		if ( isActive() ) {
			internalGetTransactionDriverControl().markRollbackOnly();
		}
		// else noop for an inactive transaction
	}

	@Override
	public void setRollbackOnly() {
		if ( !isActive() ) {
			if ( jpaCompliance ) {
				// 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 {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Guard the call: if (tx.isActive()) { tx.setRollbackOnly(); }
  2. Prefer native markRollbackOnly() when lenient behavior is desired across mixed paths
  3. Move setRollbackOnly() into the branch that actually owns the failed transaction

Example fix

// before
catch (BusinessException e) {
    tx.setRollbackOnly(); // inactive tx, JPA mode -> IllegalStateException
}

// after
catch (BusinessException e) {
    if (tx.isActive()) {
        tx.setRollbackOnly();
    }
}
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: tx.setRollbackOnly() called before begin() or after commit()/rollback() completed, with hibernate.jpa.compliance.transaction=true.

Common situations: Exception handlers marking rollback-only even on paths where no transaction ever started; shared validation/audit code running both inside and outside transactions; retry loops calling setRollbackOnly before restarting work.

Related errors


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