hibernate/hibernate-orm · error · HibernateException

Unable to locate current JTA transaction

Error message

Unable to locate current JTA transaction

What it means

JTASessionContext keys current sessions by JTA transaction. transactionManager.getTransaction() returned null, meaning no transaction is associated with the calling thread, so there is nothing to key or register a cleanup synchronization against, and Hibernate fails fast with this HibernateException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/context/internal/JTASessionContext.java:102

		try {
			txn.registerSynchronization( buildCleanupSynch( txnIdentifier ) );
		}
		catch ( Throwable t ) {
			try {
				currentSession.close();
			}
			catch ( Throwable e ) {
				CURRENT_SESSION_LOGGER.unableToReleaseGeneratedCurrentSessionOnFailedSynchronizationRegistration(e);
			}
			throw new HibernateException( "Unable to register cleanup Synchronization with TransactionManager" );
		}
	}

	private static @Nonnull Transaction getTransaction(TransactionManager transactionManager) {
		try {
			final var transaction = transactionManager.getTransaction();
			if ( transaction == null ) {
				throw new HibernateException( "Unable to locate current JTA transaction" );
			}
			if ( !isActive( transaction.getStatus() ) ) {
				// We could register the session against the transaction even though it is
				// not started, but we'd have no guarantee of ever getting the map
				// entries cleaned up (aside from spawning threads).
				throw new HibernateException( "Current transaction is not in progress" );
			}
			return transaction;
		}
		catch ( HibernateException e ) {
			throw e;
		}
		catch ( Throwable t ) {
			throw new HibernateException( "Problem locating/validating JTA transaction", t );
		}
	}

	/**

View on GitHub (pinned to fad1729dce)

Solutions

  1. Start the transaction before accessing the current session: UserTransaction.begin(), @Transactional (with proper propagation), or container-managed start
  2. For non-transactional code paths use sessionFactory.openSession() in try-with-resources instead
  3. Fix interceptor/filter ordering so the transaction boundary wraps the session access
  4. In tests, make the test itself transactional (@Transactional test) or open sessions explicitly

Example fix

// before
Session s = sessionFactory.getCurrentSession(); // no JTA tx on thread -> throws

// after
userTransaction.begin();
try {
    Session s = sessionFactory.getCurrentSession();
    ...
    userTransaction.commit();
} catch (Exception e) {
    userTransaction.rollback();
}
Defensive patterns

Strategy: validation

Validate before calling

TransactionManager tm = platform.retrieveTransactionManager();
if (tm.getTransaction() == null) {
    userTransaction.begin(); // ensure a transaction exists before asking for the current session
}
Session s = sessionFactory.getCurrentSession();

Try / catch

try {
    return sessionFactory.getCurrentSession();
} catch (org.hibernate.HibernateException e) {
    if (e.getMessage().contains("Unable to locate current JTA transaction")) {
        userTransaction.begin();
        return sessionFactory.getCurrentSession(); // retry inside the newly begun transaction
    }
    throw e;
}

Prevention

When it happens

Trigger: getCurrentSession() with JTA context before any transaction exists: before UserTransaction.begin() in SE, outside a CMT/@Transactional boundary, in @PostConstruct/servlet-filter code that runs before the transaction interceptor, or on a bare worker thread.

Common situations: Missing @Transactional on the entry method; interceptor/AOP ordering putting Hibernate access before the transaction interceptor; schedulers and executor tasks reusing getCurrentSession(); tests calling repositories without a wrapping transaction.

Related errors


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