hibernate/hibernate-orm · error · TransactionException

JTA UserTransaction.begin() failed

Error message

JTA UserTransaction.begin() failed

What it means

The UserTransaction-based JTA adapter's begin(): it calls UserTransaction.begin() when it just observed status NOT_ACTIVE and wraps any exception in this TransactionException. UserTransaction is the application-facing JTA handle; the wrapped exception (NotSupportedException/SystemException/IllegalStateException) means the UT refused to start a transaction - commonly because a transaction is already associated with the thread or the UT is unusable in the current context.

Source

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

	public JtaTransactionAdapterUserTransactionImpl(@Nonnull UserTransaction userTransaction) {
		this.userTransaction = userTransaction;
	}

	@Override
	public void begin() {
		try {
			if ( getStatus() == TransactionStatus.NOT_ACTIVE ) {
				JTA_LOGGER.callingUserTransactionBegin();
				userTransaction.begin();
				initiator = true;
				JTA_LOGGER.calledUserTransactionBegin();
			}
			else {
				JTA_LOGGER.skippingTransactionManagerBegin();
			}
		}
		catch (Exception e) {
			throw new TransactionException( "JTA UserTransaction.begin() failed", e );
		}
	}

	@Override
	public void commit() {
		try {
			if ( initiator ) {
				initiator = false;
				JTA_LOGGER.callingUserTransactionCommit();
				userTransaction.commit();
				JTA_LOGGER.calledUserTransactionCommit();
			}
			else {
				JTA_LOGGER.skippingTransactionManagerCommit();
			}
		}
		catch (Exception e) {
			throw new TransactionException( "JTA UserTransaction.commit() failed", e );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check UserTransaction.getStatus() before beginning; only begin when no transaction is active
  2. Drop the preferUserTransactions setting so the coordinator drives the TransactionManager instead
  3. Verify the JNDI name / JtaPlatform used to obtain the UserTransaction
  4. Use container-managed transaction demarcation in EE environments

Example fix

// before
UserTransaction ut = ...;
ut.begin(); // inside an already-active container-managed tx

// after
if ( ut.getStatus() == jakarta.transaction.Status.STATUS_NO_TRANSACTION ) {
    ut.begin();
}
Defensive patterns

Strategy: validation

Validate before calling

// Only begin via UserTransaction when none is active
if ( ut.getStatus() == jakarta.transaction.Status.STATUS_NO_TRANSACTION ) {
    ut.begin();
}
else {
    throw new IllegalStateException("A JTA transaction is already active");
}

Try / catch

try {
    session.beginTransaction();
}
catch (TransactionException e) {
    Throwable c = e.getCause();
    if ( c instanceof IllegalStateException || c instanceof NotSupportedException ) {
        // UserTransaction refused: a tx is already associated or UT unusable here
    }
    throw e;
}

Prevention

When it happens

Trigger: Transaction.begin() on a session whose coordinator prefers UserTransactions (preferUserTransactions) when UserTransaction.begin() throws: a container-managed transaction already active on the thread (raced status check), the container forbidding user transactions on that thread, or the UT not bound/usable.

Common situations: Calling beginTransaction() during a container-managed transaction; a UserTransaction JNDI binding valid only inside EE components; invoking from unmanaged threads; SE setups with no bound UserTransaction.

Related errors


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