{"record":{"id":"b47eaf46d53213e4","repo":"hibernate/hibernate-orm","slug":"explicitly-joining-a-jta-transaction-requires-a-jt-b47eaf","errorCode":null,"errorMessage":"Explicitly joining a JTA transaction requires a JTA transaction be currently active","messagePattern":"Explicitly joining a JTA transaction requires a JTA transaction be currently active","errorType":"exception","errorClass":"TransactionRequiredForJoinException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java","lineNumber":172,"sourceCode":"\t\tif ( !synchronizationRegistered ) {\n\t\t\tjtaPlatform.registerSynchronization(\n\t\t\t\t\tnew RegisteredSynchronization( getSynchronizationCallbackCoordinator() ) );\n\t\t\tgetSynchronizationCallbackCoordinator().synchronizationRegistered();\n\t\t\tsynchronizationRegistered = true;\n\t\t\tJTA_LOGGER.registeredSynchronization();\n\t\t\t// report entering into a \"transactional context\"\n\t\t\tgetTransactionCoordinatorOwner().startTransactionBoundary();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void explicitJoin() {\n\t\tif ( synchronizationRegistered ) {\n\t\t\tJTA_LOGGER.alreadyJoinedJtaTransaction();\n\t\t}\n\t\telse {\n\t\t\tif ( getTransactionDriverControl().getStatus() != ACTIVE ) {\n\t\t\t\tthrow new TransactionRequiredForJoinException(\n\t\t\t\t\t\t\"Explicitly joining a JTA transaction requires a JTA transaction be currently active\"\n\t\t\t\t);\n\t\t\t}\n\t\t\tjoinJtaTransaction();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isJoined() {\n\t\treturn synchronizationRegistered;\n\t}\n\n\t/**\n\t * Is the RegisteredSynchronization used by Hibernate for unified JTA Synchronization callbacks registered for this\n\t * coordinator?\n\t *\n\t * @return {@code true} indicates that a RegisteredSynchronization is currently registered for this coordinator;\n\t * {@code false} indicates it is not (yet) registered.","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Start the JTA transaction first (JTA-based @Transactional or UserTransaction.begin()) and only then call joinTransaction","With Spring, use JtaTransactionManager so Spring-managed transactions are JTA transactions","If JTA is not intended, configure Hibernate with the JDBC/resource-local transaction coordinator instead of jta","Guard with a TransactionManager status check before joining (see validation)"],"exampleFix":"// before\nem.joinTransaction(); // throws if no JTA transaction is active\n\n// after\nif ( !em.isJoinedToTransaction() ) {\n    if ( tm.getStatus() == jakarta.transaction.Status.STATUS_ACTIVE ) {\n        em.joinTransaction();\n    }\n    else {\n        ut.begin();\n        try {\n            em.joinTransaction();\n        }\n        catch (RuntimeException e) {\n            ut.rollback();\n            throw e;\n        }\n    }\n}","handlingStrategy":"validation","validationCode":"// Run this before em.joinTransaction()\ntry {\n    if ( !em.isJoinedToTransaction()\n            && transactionManager.getStatus() != jakarta.transaction.Status.STATUS_ACTIVE ) {\n        throw new IllegalStateException(\"Start the JTA transaction before joining\");\n    }\n}\ncatch (SystemException e) {\n    throw new IllegalStateException(\"Cannot determine JTA status\", e);\n}\nem.joinTransaction();","typeGuard":null,"tryCatchPattern":"try {\n    em.joinTransaction();\n}\ncatch (TransactionRequiredForJoinException e) {\n    // no JTA tx on the thread: start one (or run under JTA-based @Transactional) and retry once\n    ut.begin();\n    try {\n        em.joinTransaction();\n    }\n    catch (RuntimeException re) {\n        ut.rollback();\n        throw re;\n    }\n}","preventionTips":["Always run joinTransaction() inside a JTA-based transactional scope (@Transactional, UserTransaction.begin, CMT)","With Spring, pair a JTA-configured Hibernate with JtaTransactionManager","Prefer SYNCHRONIZED persistence contexts unless you explicitly manage joining"],"tags":["jta","transactions","hibernate","join-transaction","persistence-context"],"backgroundTag":"no-active-transaction","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}