hibernate/hibernate-orm · error · IllegalStateException

Cannot begin Transaction on closed Session/EntityManager

Error message

Cannot begin Transaction on closed Session/EntityManager

What it means

TransactionImpl.begin() first checks session.isOpen(); a closed Session/EntityManager can no longer coordinate a physical transaction, so begin() throws IllegalStateException instead of resurrecting it. This mirrors the JPA rule that a closed EntityManager is unusable.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java:61

						.isJpaTransactionComplianceEnabled();

		if ( session.isOpen() && transactionCoordinator.isActive() ) {
			transactionDriverControl =
					transactionCoordinator.getTransactionDriverControl();
		}
		else {
			CORE_LOGGER.transactionCreatedOnClosedSession();
		}

		if ( CORE_LOGGER.isDebugEnabled() && jpaCompliance ) {
			CORE_LOGGER.transactionCreatedInJpaCompliantMode();
		}
	}

	@Override
	public void begin() {
		if ( !session.isOpen() ) {
			throw new IllegalStateException( "Cannot begin Transaction on closed Session/EntityManager" );
		}

		if ( transactionDriverControl == null ) {
			transactionDriverControl =
					transactionCoordinator.getTransactionDriverControl();
		}

		if ( isActive() ) {
			if ( jpaCompliance ) {
				throw new IllegalStateException( "Transaction already active (in JPA compliant mode)" );
			}
			else if ( !transactionCoordinator.getTransactionCoordinatorBuilder().isJta() ) {
				throw new IllegalStateException( "Resource-local transaction already active" );
			}
		}
		else {
			CORE_LOGGER.beginningTransaction();
			transactionDriverControl.begin();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Get a fresh EntityManager/Session from the factory instead of reusing the closed instance
  2. Check session.isOpen() before begin() and reopen or fail with a clear message when closed
  3. Fix lifecycle ownership: the component that begins the transaction should also own (and close) the session

Example fix

// before
EntityManager em = cachedEm; // may already be closed
em.getTransaction().begin(); // IllegalStateException

// after
if (!em.isOpen()) {
    em = emf.createEntityManager();
}
em.getTransaction().begin();
Defensive patterns

Strategy: validation

Validate before calling

if (!session.isOpen()) {
    session = sessionFactory.openSession(); // or emf.createEntityManager()
}
session.beginTransaction();

Try / catch

try {
    em.getTransaction().begin();
} catch (IllegalStateException e) {
    if (String.valueOf(e.getMessage()).contains("closed Session")) {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: em.getTransaction().begin() or session.beginTransaction() after em.close()/session.close(); the same call on a session closed by a container filter (Open EntityManager in View), an earlier exception, or another thread sharing the session.

Common situations: An EntityManager cached in a field, HttpSession attribute, or singleton bean reused after the owning request closed it; closing order bugs in @PreDestroy or try-with-resources; tests that close the EM in setup but keep using it; a shared session accessed concurrently so one thread closes it mid-use.

Related errors


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