hibernate/hibernate-orm · error · IllegalStateException

Physical-transaction delegate is no longer valid

Error message

Physical-transaction delegate is no longer valid

What it means

TransactionDriverControlImpl is the per-coordinator handle through which Hibernate's Transaction API drives the JTA adapter; once the coordinator invalidates it (invalidate() sets the flag after the JTA transaction cycle completed), any further begin()/commit()/rollback() throws this IllegalStateException. It means code is driving a Session/Transaction whose JTA transaction already finished - typically a cached Transaction reused after completion, a second commit, or begin() on a stale delegate.

Source

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

		public TransactionDriverControlImpl(@Nonnull JtaTransactionAdapter jtaTransactionAdapter) {
			this.jtaTransactionAdapter = jtaTransactionAdapter;
		}

		protected void invalidate() {
			invalid = true;
		}

		@Override
		public void begin() {
			errorIfInvalid();
			jtaTransactionAdapter.begin();
			joinJtaTransaction();
		}

		protected void errorIfInvalid() {
			if ( invalid ) {
				throw new IllegalStateException( "Physical-transaction delegate is no longer valid" );
			}
		}

		@Override
		public void commit() {
			errorIfInvalid();
			getTransactionCoordinatorOwner().flushBeforeTransactionCompletion();
			// we don't have to perform any before/after completion processing here.  We leave that for
			// the Synchronization callbacks
			jtaTransactionAdapter.commit();
		}

		@Override
		public void rollback() {
			errorIfInvalid();
			// we don't have to perform any after completion processing here.  We leave that for
			// the Synchronization callbacks
			jtaTransactionAdapter.rollback();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use a fresh Session (and its Transaction) per unit of work; never cache Transaction instances
  2. Check Transaction.getStatus() before begin/commit and re-open the session when the delegate is stale
  3. Make retry loops begin a new transaction rather than recommitting the old one
  4. For extended contexts rely on container-managed patterns (OSIV / extended persistence context) instead of manual session reuse

Example fix

// before: transaction cached and reused after completion
private final Transaction tx = session.getTransaction();
void run() {
    tx.commit();
    tx.begin(); // IllegalStateException: delegate invalidated
}

// after: new session + transaction per unit of work
void run() {
    try (Session s = sessionFactory.openSession()) {
        s.beginTransaction();
        // ... work ...
        s.getTransaction().commit();
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Check before driving a possibly-stale Transaction
TransactionStatus st = tx.getStatus();
if ( st != TransactionStatus.NOT_ACTIVE && st != TransactionStatus.ACTIVE
        && st != TransactionStatus.MARKED_ROLLBACK ) {
    // delegate invalidated by a completed JTA tx: get a fresh session/transaction
    session = sessionFactory.openSession();
    tx = session.getTransaction();
}

Try / catch

try {
    tx.begin();
}
catch (IllegalStateException e) {
    if ( e.getMessage() != null && e.getMessage().contains("no longer valid") ) {
        // stale delegate: open a new session and start a fresh transaction
        try (Session fresh = sessionFactory.openSession()) {
            fresh.beginTransaction();
            // redo the unit of work
        }
    }
    else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling begin(), commit() or rollback() on a Transaction whose delegate was invalidated: tx.commit() invoked twice; a Transaction or Session stored in a field/ThreadLocal and reused across requests; retry logic reusing the same transaction; extended-session patterns on JTA backends.

Common situations: Long-lived Sessions reused across container-managed transactions; cached Transaction objects; catch-and-retry loops that recommit; helpers that begin 'if not active' against a coordinator whose transaction already completed.

Related errors


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