hibernate/hibernate-orm · error · TransactionException

JTA TransactionManager.rollback() failed

Error message

JTA TransactionManager.rollback() failed

What it means

TransactionManager.rollback() threw while executing Transaction.rollback(); wrapped causes are usually SystemException or IllegalStateException, for example when the transaction already completed (a TM timeout finished it, or the container rolled it back) or rollback is invoked from a non-owner thread. Hibernate only calls rollback when it was the initiator - otherwise it marks rollback-only. This exception says the explicit rollback could not complete; the original business error, if any, is separate.

Source

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

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

	@Override
	public void rollback() {
		try {
			if ( initiator ) {
				initiator = false;
				JTA_LOGGER.callingTransactionManagerRollback();
				transactionManager.rollback();
				JTA_LOGGER.calledTransactionManagerRollback();
			}
			else {
				markRollbackOnly();
			}
		}
		catch (Exception e) {
			throw new TransactionException( "JTA TransactionManager.rollback() failed", e );
		}
	}

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check tx.getStatus() before rolling back and skip when the transaction is already completed
  2. Increase the JTA transaction timeout if transactions complete before the rollback call
  3. Keep begin, commit and rollback on the same thread
  4. If SystemException persists, check TransactionManager health and logs

Example fix

// before
try { tx.commit(); }
catch (Exception e) { tx.rollback(); } // may throw 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 IllegalStateException || e.getCause() instanceof SystemException ) {
        log.warn("rollback could not complete; tx may already be gone", e);
    }
}

Prevention

When it happens

Trigger: tx.rollback() after the JTA transaction already finished (timeout fired between the failure and the rollback call, container completed it); rollback invoked from a different thread; TM internal error.

Common situations: JTA timeout completing the transaction underneath the application; asynchronous processing moving transaction work across threads; TM in recovery.

Related errors


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