hibernate/hibernate-orm · error · TransactionException

Unable to mark transaction for rollback only

Error message

Unable to mark transaction for rollback only

What it means

markRollbackOnly() on the UT adapter calls userTransaction.setRollbackOnly(); a SystemException is wrapped as 'Unable to mark transaction for rollback only'. Reached via Transaction.markRollbackOnly() or as rollback()'s fallback when Hibernate was not the initiator. The transaction may remain active afterwards - it must be resolved by explicit rollback, timeout, or container intervention.

Source

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

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

	@Override
	public void markRollbackOnly(){
		try {
			userTransaction.setRollbackOnly();
		}
		catch (SystemException e) {
			throw new TransactionException( "Unable to mark transaction for rollback only", e );
		}
	}

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check UserTransaction.getStatus() before marking rollback-only
  2. Inspect the SystemException cause in the TM logs
  3. If you initiated the transaction, call rollback() instead of markRollbackOnly()
  4. Restart an unhealthy TM
Defensive patterns

Strategy: validation

Validate before calling

// Mark rollback-only only inside an active UT transaction
int st = ut.getStatus();
if ( st == jakarta.transaction.Status.STATUS_ACTIVE
        || st == jakarta.transaction.Status.STATUS_MARKED_ROLLBACK ) {
    ut.setRollbackOnly();
}

Try / catch

try {
    session.getTransaction().markRollbackOnly();
}
catch (TransactionException e) {
    log.error("could not mark rollback-only; attempting full rollback", e);
    session.getTransaction().rollback();
}

Prevention

When it happens

Trigger: markRollbackOnly(), or the rollback() fallback, while userTransaction.setRollbackOnly() throws SystemException - TM internal error, no active UT transaction on the thread, or shutdown race.

Common situations: Marking rollback-only outside an active UT transaction; TM internal failure; operations during TM shutdown.

Related errors


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