hibernate/hibernate-orm · error · TransactionException

JTA UserTransaction.rollback() failed

Error message

JTA UserTransaction.rollback() failed

What it means

UserTransaction.rollback() threw while executing Transaction.rollback(); Hibernate only calls it when it initiated the transaction via the UT, otherwise it marks rollback-only. The wrapped exception (SystemException, IllegalStateException, SecurityException) means the explicit rollback could not complete - e.g., the transaction already ended via timeout, or the caller is not permitted to roll it back. The original business failure, if any, is a separate exception.

Source

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

			throw new TransactionException( "JTA UserTransaction.commit() failed", e );
		}
	}

	@Override
	public void rollback() {
		try {
			if ( initiator ) {
				initiator = false;
				JTA_LOGGER.callingUserTransactionRollback();
				userTransaction.rollback();
				JTA_LOGGER.calledUserTransactionRollback();
			}
			else {
				markRollbackOnly();
			}
		}
		catch (Exception e) {
			throw new TransactionException( "JTA UserTransaction.rollback() failed", e );
		}
	}

	@Override
	@Nonnull
	public TransactionStatus getStatus() {
		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 );
		}
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check tx.getStatus() before rollback; if it is neither ACTIVE nor MARKED_ROLLBACK, skip and log
  2. Raise the JTA timeout if transactions end prematurely
  3. Ensure rollback happens in the same context/thread that began the transaction
  4. Investigate persistent SystemException causes via TM logs

Example fix

// before
try { tx.commit(); }
catch (Exception e) { tx.rollback(); } // throws if tx already completed

// after
try { tx.commit(); }
catch (Exception e) {
    TransactionStatus st = tx.getStatus();
    if ( st == TransactionStatus.ACTIVE || st == TransactionStatus.MARKED_ROLLBACK ) {
        tx.rollback();
    }
    else {
        log.debug("transaction already completed; nothing to roll back", e);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Roll back only when the tx is still open
TransactionStatus st = tx.getStatus();
if ( st == TransactionStatus.ACTIVE || st == TransactionStatus.MARKED_ROLLBACK ) {
    tx.rollback();
}
else {
    log.debug("transaction already completed; skipping rollback");
}

Try / catch

try {
    tx.rollback();
}
catch (TransactionException e) {
    if ( e.getCause() instanceof SecurityException ) {
        // caller not permitted to roll back this UT
    }
    else {
        log.warn("rollback could not complete; tx may already be gone", e);
    }
}

Prevention

When it happens

Trigger: tx.rollback() when the JTA transaction already completed (UT/TM timeout finished it, container completed it), rollback from a context without permission, or a UT internal error.

Common situations: Timeout completing the transaction before the application's rollback call; bean-managed transactions rolled back from the wrong thread or context; TM under stress.

Related errors


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