hibernate/hibernate-orm · error · TransactionRequiredForJoinException

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

JtaTransactionCoordinatorImpl.explicitJoin() runs when the session is not yet enlisted in a JTA transaction (synchronizationRegistered == false). If the physical delegate's status is not ACTIVE it throws TransactionRequiredForJoinException: you asked to join a JTA transaction, but none is currently active on the thread. It surfaces from EntityManager.joinTransaction()/Session transaction join, most often for UNSYNCHRONIZED persistence contexts.

Source

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

		if ( !synchronizationRegistered ) {
			jtaPlatform.registerSynchronization(
					new RegisteredSynchronization( getSynchronizationCallbackCoordinator() ) );
			getSynchronizationCallbackCoordinator().synchronizationRegistered();
			synchronizationRegistered = true;
			JTA_LOGGER.registeredSynchronization();
			// report entering into a "transactional context"
			getTransactionCoordinatorOwner().startTransactionBoundary();
		}
	}

	@Override
	public void explicitJoin() {
		if ( synchronizationRegistered ) {
			JTA_LOGGER.alreadyJoinedJtaTransaction();
		}
		else {
			if ( getTransactionDriverControl().getStatus() != ACTIVE ) {
				throw new TransactionRequiredForJoinException(
						"Explicitly joining a JTA transaction requires a JTA transaction be currently active"
				);
			}
			joinJtaTransaction();
		}
	}

	@Override
	public boolean isJoined() {
		return synchronizationRegistered;
	}

	/**
	 * Is the RegisteredSynchronization used by Hibernate for unified JTA Synchronization callbacks registered for this
	 * coordinator?
	 *
	 * @return {@code true} indicates that a RegisteredSynchronization is currently registered for this coordinator;
	 * {@code false} indicates it is not (yet) registered.

View on GitHub (pinned to fad1729dce)

Solutions

  1. Start the JTA transaction first (JTA-based @Transactional or UserTransaction.begin()) and only then call joinTransaction
  2. With Spring, use JtaTransactionManager so Spring-managed transactions are JTA transactions
  3. If JTA is not intended, configure Hibernate with the JDBC/resource-local transaction coordinator instead of jta
  4. Guard with a TransactionManager status check before joining (see validation)

Example fix

// before
em.joinTransaction(); // throws if no JTA transaction is active

// after
if ( !em.isJoinedToTransaction() ) {
    if ( tm.getStatus() == jakarta.transaction.Status.STATUS_ACTIVE ) {
        em.joinTransaction();
    }
    else {
        ut.begin();
        try {
            em.joinTransaction();
        }
        catch (RuntimeException e) {
            ut.rollback();
            throw e;
        }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Run this before em.joinTransaction()
try {
    if ( !em.isJoinedToTransaction()
            && transactionManager.getStatus() != jakarta.transaction.Status.STATUS_ACTIVE ) {
        throw new IllegalStateException("Start the JTA transaction before joining");
    }
}
catch (SystemException e) {
    throw new IllegalStateException("Cannot determine JTA status", e);
}
em.joinTransaction();

Try / catch

try {
    em.joinTransaction();
}
catch (TransactionRequiredForJoinException e) {
    // no JTA tx on the thread: start one (or run under JTA-based @Transactional) and retry once
    ut.begin();
    try {
        em.joinTransaction();
    }
    catch (RuntimeException re) {
        ut.rollback();
        throw re;
    }
}

Prevention

When it happens

Trigger: em.joinTransaction() executed where no JTA transaction is active: code not running under a JTA-based @Transactional or UserTransaction.begin(); the container transaction already completed (e.g., timed out); async threads without a propagated transaction; Spring using a non-JTA PlatformTransactionManager while Hibernate is JTA-configured.

Common situations: SynchronizationType.UNSYNCHRONIZED EntityManagers calling joinTransaction at a point where the surrounding transaction has not started; Spring's DataSourceTransactionManager or HibernateTransactionManager with a jta coordinator_class; SE code forgetting UserTransaction.begin(); joining after a timeout completed the transaction.

Related errors


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