{"record":{"id":"414f2b375e4db29d","repo":"hibernate/hibernate-orm","slug":"calling-method-methodname-is-not-valid-without","errorCode":null,"errorMessage":"Calling method '{methodName}' is not valid without an active transaction (Current status: {status})","messagePattern":"Calling method '(.+?)' is not valid without an active transaction \\(Current status: (.+?)\\)","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java","lineNumber":327,"sourceCode":"\t\t\t\t\t// above has the same basic effect, but we capture that there\n\t\t\t\t\t// just to unbind().\n\t\t\t\t\tCURRENT_SESSION_LOGGER.allowingInvocationToProceedToClosedSession(methodName);\n\t\t\t\t}\n\t\t\t\telse if ( realSession.getTransaction().getStatus() != TransactionStatus.ACTIVE ) {\n\t\t\t\t\t// limit the methods available if no transaction is active\n\t\t\t\t\tif ( \"beginTransaction\".equals( methodName )\n\t\t\t\t\t\t\t|| \"getTransaction\".equals( methodName )\n\t\t\t\t\t\t\t|| \"isTransactionInProgress\".equals( methodName )\n\t\t\t\t\t\t\t|| \"setFlushMode\".equals( methodName )\n\t\t\t\t\t\t\t|| \"setHibernateFlushMode\".equals( methodName )\n\t\t\t\t\t\t\t|| \"getFactory\".equals( methodName )\n\t\t\t\t\t\t\t|| \"getSessionFactory\".equals( methodName )\n\t\t\t\t\t\t\t|| \"getJdbcCoordinator\".equals( methodName )\n\t\t\t\t\t\t\t|| \"getTenantIdentifier\".equals( methodName ) ) {\n\t\t\t\t\t\tCURRENT_SESSION_LOGGER.allowingInvocationToProceedToNonTransactedSession(methodName);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthrow new HibernateException( \"Calling method '\" + methodName\n\t\t\t\t\t\t\t\t+ \"' is not valid without an active transaction (Current status: \"\n\t\t\t\t\t\t\t\t+ realSession.getTransaction().getStatus() + \")\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn method.invoke( realSession, args );\n\t\t\t}\n\t\t\tcatch ( InvocationTargetException e ) {\n\t\t\t\tif (e.getTargetException() instanceof RuntimeException) {\n\t\t\t\t\tthrow e.getTargetException();\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Setter for property 'wrapped'.\n\t\t *\n\t\t * @param wrapped Value to set for property 'wrapped'.","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java#L309-L345","documentation":"ThreadLocalSessionContext hands out a transaction-protection proxy: when no transaction is active on the session, only a whitelist of methods may proceed (beginTransaction, getTransaction, isTransactionInProgress, setFlushMode, setHibernateFlushMode, getFactory, getSessionFactory, getJdbcCoordinator, getTenantIdentifier). Any other invocation — persist, find, createQuery, close — throws this HibernateException naming the method and the current transaction status.","triggerScenarios":"hibernate.current_session_context_class=thread and calling e.g. session.persist(user) or session.find(...) on getCurrentSession() before beginTransaction(), or after the previous transaction committed and no new one started.","commonSituations":"Read-only code paths written without an explicit transaction on the assumption that auto-commit reads work; code migrated from JTA-managed environments where the container guaranteed a transaction; utility/helper classes lazily fetching getCurrentSession(); test harnesses opening sessions without a transaction.","solutions":["Begin a transaction first: sessionFactory.getCurrentSession().beginTransaction() is whitelisted and safe to call","For genuinely non-transactional reads use sessionFactory.openSession() in try-with-resources","Set hibernate.current_session_context_class to match the runtime (jta, managed, or the Spring-provided context) instead of thread","Wrap each work unit so begin/commit lives in one place (template/DAO base) instead of relying on callers"],"exampleFix":"// before\nSession s = sessionFactory.getCurrentSession();\ns.persist(user); // throws: no active transaction\n\n// after\nSession s = sessionFactory.getCurrentSession();\ns.beginTransaction();\ns.persist(user);\ns.getTransaction().commit();","handlingStrategy":"validation","validationCode":"Session s = sessionFactory.getCurrentSession();\nif (!s.isTransactionInProgress()) { // whitelisted method, safe on the proxy\n    s.beginTransaction();\n}\ns.persist(user);","typeGuard":null,"tryCatchPattern":"try {\n    session.persist(user);\n} catch (org.hibernate.HibernateException e) {\n    if (e.getMessage().contains(\"is not valid without an active transaction\")) {\n        session.beginTransaction(); // begin is whitelisted; retry once inside the transaction\n        session.persist(user);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Wrap all current-session work in begin/commit via one shared template","Use openSession() for non-transactional reads instead of bypassing the proxy","Match hibernate.current_session_context_class to the actual runtime environment"],"tags":["hibernate","transaction","thread-local-session-context","current-session","configuration"],"backgroundTag":"no-active-transaction","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}