hibernate/hibernate-orm · error · IllegalStateException

EntityManager was already closed

Error message

EntityManager was already closed

What it means

SessionImpl.close() mirrors the factory: closing twice is normally just logged, but with JPA closed compliance enabled (hibernate.jpa.compliance.closed) the second close throws IllegalStateException('EntityManager was already closed'). The check runs after checkSessionReentrancy(), so closing from within the session's own callback also fails. JPA containers rely on this strictness.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java:352

	}

	private void internalClear() {
		persistenceContext.clear();
		actionQueue.clear();
		eventListenerGroups.eventListenerGroup_CLEAR
				.fireLazyEventOnEachListener( this::createClearEvent, ClearEventListener::onClear );
	}

	private ClearEvent createClearEvent() {
		return new ClearEvent( this );
	}

	@Override
	public void close() {
		checkSessionReentrancy();
		if ( isClosed() ) {
			if ( getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) {
				throw new IllegalStateException( "EntityManager was already closed" );
			}
			SESSION_LOGGER.alreadyClosed();
		}
		else {
			final var preCloseException = getFactory().preClose( this );
			try {
				closeWithoutOpenChecks();
			}
			catch (RuntimeException e) {
				if ( preCloseException != null ) {
					e.addSuppressed( preCloseException );
				}
				throw e;
			}
			if ( preCloseException != null ) {
				throw preCloseException;
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Guard every close: if (em != null && em.isOpen()) em.close();
  2. Use exactly one close strategy per EM — try-with-resources OR container management, never both
  3. In decorators, forward isOpen() and only close what you own
  4. Never explicitly close container-managed (injected @PersistenceContext) EntityManagers

Example fix

// before
try (EntityManager em = emf.createEntityManager()) {
    // ...
} // container/proxy also closes -> IllegalStateException under compliance

// after
EntityManager em = emf.createEntityManager();
try {
    // ...
} finally {
    if (em.isOpen()) {
        em.close(); // single, guarded close
    }
}
Defensive patterns

Strategy: validation

Validate before calling

public static void closeQuietly(EntityManager em) {
    if (em != null && em.isOpen()) {
        em.close();
    }
}

Try / catch

try {
    em.close();
} catch (IllegalStateException e) {
    // already closed under JPA compliance — idempotent close, safe to ignore
    LOG.debug("EntityManager already closed", e);
}

Prevention

When it happens

Trigger: Calling close() twice on the same Session/EntityManager with compliance enabled — e.g. try-with-resources plus a manual close, or an application-layer decorator and the container both closing. Note close() also swallows nothing: if the first close threw mid-way, status may not be CLOSED and behavior differs.

Common situations: Wrapper/decorator EntityManager beans whose close() delegates and also closes the delegate; finally blocks plus try-with-resources around the same EM; servlet filters closing injected container-managed EMs (which the container also closes); enabling compliance in Quarkus/Spring and surfacing latent double closes.

Related errors


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