hibernate/hibernate-orm · error · TransactionException

Could not set transaction to rollback only

Error message

Could not set transaction to rollback only

What it means

markRollbackOnly() calls TransactionManager.setRollbackOnly(); a SystemException from the TM is wrapped as 'Could not set transaction to rollback only'. This is the safe path failing after a business error - the transaction may still be active and must be resolved by explicit rollback, timeout, or container intervention. Reached via Transaction.markRollbackOnly(), and via rollback() when Hibernate was not the initiator (which falls back to marking rollback-only).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionAdapterTransactionManagerImpl.java:106

		try {
			final var status = StatusTranslator.translate( transactionManager.getStatus() );
			if ( status == null ) {
				throw new TransactionException( "TransactionManager reported transaction status as unknown" );
			}
			return status;
		}
		catch (SystemException e) {
			throw new TransactionException( "JTA TransactionManager#getStatus failed", e );
		}
	}

	@Override
	public void markRollbackOnly() {
		try {
			transactionManager.setRollbackOnly();
		}
		catch (SystemException e) {
			throw new TransactionException( "Could not set transaction to rollback only", e );
		}
	}

	@Override
	public void setTimeOut(int seconds) {
		if ( seconds > 0 ) {
			try {
				transactionManager.setTransactionTimeout( seconds );
			}
			catch (SystemException e) {
				throw new TransactionException( "Unable to apply requested transaction timeout", e );
			}
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check TransactionManager.getStatus() before marking rollback-only
  2. Inspect the SystemException cause in the TM logs
  3. If Hibernate initiated the transaction, call rollback() directly instead of markRollbackOnly()
  4. Restart the TM if it is unhealthy
Defensive patterns

Strategy: validation

Validate before calling

// Mark rollback-only only inside an active transaction
if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE
        || session.getTransaction().getStatus() == TransactionStatus.MARKED_ROLLBACK ) {
    session.getTransaction().markRollbackOnly();
}

Try / catch

try {
    tx.markRollbackOnly();
}
catch (TransactionException e) {
    log.error("could not mark rollback-only; attempting full rollback instead", e);
    tx.rollback(); // may succeed where setRollbackOnly failed
}

Prevention

When it happens

Trigger: session.getTransaction().markRollbackOnly(), or the rollback() fallback on a non-initiated transaction, while TransactionManager.setRollbackOnly() throws SystemException - TM internal error, TM shutting down, or no usable transaction on the thread.

Common situations: TM internal failure; marking rollback-only with no active JTA transaction; races during application shutdown.

Related errors


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