hibernate/hibernate-orm · error · HibernateException

Unable to register cleanup Synchronization with TransactionM

Error message

Unable to register cleanup Synchronization with TransactionManager

What it means

After building a session for the current JTA transaction, JTASessionContext registers a Synchronization on that transaction so the session is removed from the map when the transaction completes. If Transaction.registerSynchronization() throws — transaction already completed, marked rollback-only, or TM-specific restrictions — Hibernate closes the freshly built session and throws this HibernateException.

Source

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

		else {
			validateExistingSession( currentSession );
		}

		return currentSession;
	}

	private void registerSynchronization(Transaction txn, Object txnIdentifier, Session currentSession) {
		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 ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Move current-session access earlier, well before the transaction can complete
  2. Check the transaction status is STATUS_ACTIVE before calling getCurrentSession() and skip or fast-fail otherwise
  3. Find the earlier failure that marked the transaction rollback-only — that exception is the root cause, not this one
  4. For work that must run after completion, open a plain sessionFactory.openSession() with its own short transaction

Example fix

// before
public void afterCompletion() {
    sessionFactory.getCurrentSession().persist(audit); // dying tx -> sync registration fails
}

// after
public void afterCompletion() {
    try (Session s = sessionFactory.openSession()) {
        s.beginTransaction();
        s.persist(audit);
        s.getTransaction().commit();
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

TransactionManager tm = platform.retrieveTransactionManager();
if (tm.getStatus() == jakarta.transaction.Status.STATUS_ACTIVE) {
    Session s = sessionFactory.getCurrentSession(); // safe: sync registration will succeed
}

Try / catch

try {
    return sessionFactory.getCurrentSession();
} catch (org.hibernate.HibernateException e) {
    if (e.getMessage().contains("register cleanup Synchronization")) {
        // session was already closed by Hibernate; run the work in a fresh transaction instead of retrying
        return runInNewTransaction(this::doWork);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling getCurrentSession() when the JTA transaction is in a state that no longer accepts synchronizations: after it was marked rollback-only by an earlier failure, while it is preparing/completing, from afterCompletion-style callbacks, or when another component's synchronization registration poisoned the transaction.

Common situations: First DB access happening in the tail of a dying transaction (@PreDestroy, afterCompletion hooks, async handoff from a request thread); a previous exception marked the TX rollback-only but processing continued; transaction timeouts racing session access.

Related errors


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