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

  1. Guard the read: boolean rollbackOnly = tx.isActive() && tx.getRollbackOnly();
  2. Restrict flag polling to code that provably runs inside the begun transaction
  3. 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

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


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