hibernate/hibernate-orm · error · TransactionRequiredException

Explicitly joining a JTA transaction requires a JTA transact

Error message

Explicitly joining a JTA transaction requires a JTA transaction be currently active

What it means

joinTransaction()/EntityManager.joinTransaction() asks the JTA TransactionCoordinator to explicitly join the current JTA transaction. The coordinator raises TransactionRequiredForJoinException when no JTA transaction is active on the thread; AbstractSharedSessionContract converts it to jakarta.persistence.TransactionRequiredException with this message. Joining is only meaningful when a JTA transaction exists to join.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java:1416

			}
			catch (HibernateException e) {
				throw e;
			}
			catch (RuntimeException e) {
				throw new HibernateException( "Exception pulsing TransactionCoordinator", e );
			}
		}
	}

	@Override
	public void joinTransaction() {
		checkOpen();
		try {
			// For a non-JTA TransactionCoordinator, this just logs a WARNing
			transactionCoordinator.explicitJoin();
		}
		catch ( TransactionRequiredForJoinException e ) {
			throw new TransactionRequiredException( e.getMessage() );
		}
		catch ( HibernateException he ) {
			throw getExceptionConverter().convert( he );
		}
	}

	@Override
	public boolean isJoinedToTransaction() {
		checkOpen();
		return transactionCoordinator.isJoined();
	}

	protected void delayedAfterCompletion() {
		if ( transactionCoordinator instanceof JtaTransactionCoordinatorImpl jtaTransactionCoordinator ) {
			jtaTransactionCoordinator.getSynchronizationCallbackCoordinator().processAnyDelayedAfterCompletion();
		}
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call joinTransaction() only inside an active JTA transaction — annotate the method @Transactional (REQUIRED) so the container starts one.
  2. If the work legitimately needs no transaction, drop the joinTransaction() call entirely.
  3. Check JTA status first via UserTransaction/TransactionManager and skip the join when STATUS_NO_TRANSACTION.

Example fix

// before
public void run() { em.joinTransaction(); process(); } // throws if no JTA tx
// after
@Transactional
public void run() { em.joinTransaction(); process(); } // tx active, join succeeds
Defensive patterns

Strategy: validation

Validate before calling

if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) {
    em.joinTransaction();
} // else: nothing to join; proceed without or start a transaction first

Try / catch

try {
    em.joinTransaction();
} catch (TransactionRequiredException e) {
    // decide: start a transaction, or skip the join — never ignore silently
    userTransaction.begin();
    em.joinTransaction();
}

Prevention

When it happens

Trigger: em.joinTransaction() called with no active JTA transaction: inside @TransactionAttribute(NOT_SUPPORTS/NEVER), before the container started the transaction, from background threads, or in code assuming a transaction that the caller never started.

Common situations: Porting between app servers or to Quarkus/Spring; defensively calling joinTransaction 'for safety' in scheduled jobs or batch steps; unit tests without a transactional context; a JTA TransactionManager configured but the business method not annotated @Transactional.

Related errors


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