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
- Call joinTransaction() only inside an active JTA transaction — annotate the method @Transactional (REQUIRED) so the container starts one.
- If the work legitimately needs no transaction, drop the joinTransaction() call entirely.
- 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
- Call joinTransaction() only from methods already demarcated @Transactional
- In jobs and batch steps, start the JTA transaction explicitly before joining
- Delete defensive joinTransaction() calls in code that has no transaction semantics
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
- Transaction is not accessible when using JTA with JPA-compli
- Exception pulsing TransactionCoordinator
- Unable to start isolated transaction
- Error performing work
- JTA TransactionManager.begin() failed
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e64c9d1a2d2ea0d9.
Report an issue: GitHub.