hibernate/hibernate-orm · error · IllegalStateException
{} is closed
Error message
{} is closed What it means
AbstractLogicalConnectionImplementor backs the logical JDBC connection of every Hibernate Session/EntityManager. Operations that need the physical transaction handle call errorIfClosed() first, which throws IllegalStateException('<LogicalConnectionImpl...> is closed') once the logical connection - i.e. the session - has been closed. Any use of a closed session's connection/transaction layer trips this guard.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/AbstractLogicalConnectionImplementor.java:39
* Base support for {@link LogicalConnection} implementations
*
* @author Steve Ebersole
*/
public abstract class AbstractLogicalConnectionImplementor implements LogicalConnectionImplementor, PhysicalJdbcTransaction {
@Nonnull
private TransactionStatus status = TransactionStatus.NOT_ACTIVE;
@Override
@Nonnull
public PhysicalJdbcTransaction getPhysicalJdbcTransaction() {
errorIfClosed();
return this;
}
protected void errorIfClosed() {
if ( !isOpen() ) {
throw new IllegalStateException( this + " is closed" );
}
}
@Override
public void afterStatement() {
}
@Override
public void beforeTransactionCompletion() {
}
@Override
public void afterTransaction() {
getResourceRegistry().releaseResources();
}
// PhysicalJdbcTransaction impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
View on GitHub (pinned to fad1729dce)
Solutions
- Guard with isOpen() before using a possibly-closed session, or restructure to try-with-resources so close is always the last operation.
- Complete lazy loading before closing: use join fetch, EntityGraphs, or DTO projections instead of lazy proxies that outlive the session.
- Keep EntityManager usage single-threaded and never reuse one after close().
- Catch IllegalStateException around the affected block to convert it into a domain-meaningful error (e.g. 'operation on detached data').
Example fix
// before
em.close();
// ... later ...
em.getTransaction().commit(); // IllegalStateException: LogicalConnection... is closed
// after
try (EntityManager em = emf.createEntityManager()) {
em.getTransaction().begin();
// work
em.getTransaction().commit();
} // close always happens last Defensive patterns
Strategy: validation
Validate before calling
// guard shared helpers that may run after close
static void requireOpen(EntityManager em) {
if (!em.isOpen()) {
throw new IllegalStateException("EntityManager is closed; open a new one for this operation");
}
}
requireOpen(em);
em.getTransaction().commit(); Try / catch
try {
em.getTransaction().commit();
} catch (IllegalStateException e) {
// '<LogicalConnection...> is closed': session was closed before commit
// treat as a usage bug (closed/detached access), not a retryable failure
throw new SessionLifecycleException("Operation on closed session", e);
} Prevention
- Use try-with-resources for EntityManager/Session lifecycles so close is always last.
- Fetch all lazy data before closing (join fetch, EntityGraph, DTO projection).
- Never share an EntityManager across threads or reuse it after close().
- Add isOpen() guards in shared helper/util code that receives sessions.
When it happens
Trigger: Calling getTransaction().begin()/commit(), obtaining the connection, or running any JDBC-level operation on a Session/EntityManager that was already closed; typically lazy loading, commit, or shared-helper access that runs after em.close().
Common situations: Lazy proxies or detached graphs accessed after the session closed; entity managers shared across threads where one thread closes while another still uses it; async processing holding a stale EM; missing try-with-resources so close happens earlier than expected.
Related errors
- Cannot serialize Session while connected
- Session/EntityManager is closed
- EntityManager was already closed
- Logical connection is closed
- The ClassLoaderService cannot be reused (this instance was s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/edba7de00d9afac0.
Report an issue: GitHub.