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
- Guard every close: if (em != null && em.isOpen()) em.close();
- Use exactly one close strategy per EM — try-with-resources OR container management, never both
- In decorators, forward isOpen() and only close what you own
- 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
- Use exactly one closing mechanism per EntityManager (try-with-resources OR container-managed)
- Never close injected @PersistenceContext EntityManagers yourself
- In decorators, delegate close() once and make isOpen() accurate
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
- EntityManagerFactory is already closed
- No child ServiceRegistry registrations found
- Session/EntityManager is closed
- EntityManagerFactory is closed
- {} is closed
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/6d00415292f63f10.
Report an issue: GitHub.