{"record":{"id":"934b90658fd7fa15","repo":"hibernate/hibernate-orm","slug":"session-entitymanager-is-closed","errorCode":null,"errorMessage":"Session/EntityManager is closed","messagePattern":"Session/EntityManager is closed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java","lineNumber":1121,"sourceCode":"\n\tprotected void cleanupOnClose() {\n\t\t// nothing to do in base impl, here for SessionImpl hook\n\t}\n\n\t@Override\n\tpublic boolean isOpenOrWaitingForAutoClose() {\n\t\treturn !closed && factory.isOpen()\n\t\t\t|| waitingForAutoClose;\n\t}\n\n\t@Override\n\tpublic void checkOpen(boolean markForRollbackIfClosed) {\n\t\tcheckSessionReentrancy();\n\t\tif ( isClosed() ) {\n\t\t\tif ( markForRollbackIfClosed && transactionCoordinator.isTransactionActive() ) {\n\t\t\t\tmarkForRollbackOnly();\n\t\t\t}\n\t\t\tthrow new IllegalStateException( \"Session/EntityManager is closed\" );\n\t\t}\n\t}\n\n\tprivate void startSessionUseProhibited() {\n\t\tsessionUseProhibitedDepth++;\n\t}\n\n\tprivate void finishSessionUseProhibited() {\n\t\tsessionUseProhibitedDepth--;\n\t}\n\n\tprotected void checkSessionReentrancy() {\n\t\tif ( sessionUseProhibitedDepth > 0 ) {\n\t\t\tthrow new IllegalStateException( \"Session method called from entity lifecycle callback or Interceptor method\" );\n\t\t}\n\t}\n\n\tprotected void checksBeforeQueryCreation() {","sourceCodeStart":1103,"sourceCodeEnd":1139,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java#L1103-L1139","documentation":"checkOpen() runs at the head of nearly every Session/EntityManager operation. If the session is closed it marks the ongoing transaction rollback-only (when asked) and throws IllegalStateException. Closing is terminal: every later call on the same session fails identically. This is the standard guard behind 'using a closed EntityManager' failures.","triggerScenarios":"Calling any session/em method after session.close(); using a container-managed EntityManager after the @Transactional method it belonged to exited; reusing a request-scoped EM in a later thread; keeping an EntityManager in a field/cache across HTTP requests.","commonSituations":"Lazy loading after the transaction closed (sibling of LazyInitializationException); try-with-resources closing the session before async/later code uses loaded objects; servlet filters closing sessions too early; retry loops reusing the same closed EM; background jobs receiving detached entities.","solutions":["Keep all entity access, including lazy navigation, inside the transactional scope that loaded the entities.","Fetch what you need up front (join fetch, EntityGraph, @Fetch) so no session is required after the boundary.","For later processing, pass IDs and reload in a fresh session/transaction instead of reusing the closed one.","If you must continue with loaded instances, open a new session and reattach via session.merge()/lock()."],"exampleFix":"// before\nList<Order> orders;\ntry (Session s = sf.openSession()) {\n    orders = s.createQuery(\"from Order\", Order.class).list();\n}\norders.get(0).getItems().size(); // IllegalStateException: session closed\n// after\nList<Order> orders;\ntry (Session s = sf.openSession()) {\n    orders = s.createQuery(\"from Order o join fetch o.items\", Order.class).list();\n} // data already loaded, safe outside","handlingStrategy":"validation","validationCode":"if (!session.isOpen()) {\n    session = sessionFactory.openSession(); // or fail explicitly\n}\nreturn session.find(Customer.class, id);","typeGuard":null,"tryCatchPattern":"try {\n    return session.find(Customer.class, id);\n} catch (IllegalStateException e) {\n    if (!session.isOpen()) {\n        try (Session fresh = sessionFactory.openSession()) {\n            return fresh.find(Customer.class, id);\n        }\n    }\n    throw e;\n}","preventionTips":["Never store EntityManager/Session in instance fields across requests","Do lazy navigation and fetching inside the transactional boundary, or join-fetch up front","Use try-with-resources scoped tightly around the code that needs the session"],"tags":["hibernate","session","entitymanager","lifecycle","lazy-loading"],"backgroundTag":"session-already-closed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}