{"record":{"id":"b10a459705c1996d","repo":"quarkusio/quarkus","slug":"not-supported-for-jta-entity-managers","errorCode":null,"errorMessage":"Not supported for JTA entity managers","messagePattern":"Not supported for JTA entity managers","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java","lineNumber":627,"sourceCode":"    public Object getDelegate() {\n        try (SessionResult emr = acquireSession()) {\n            return emr.session.getDelegate();\n        }\n    }\n\n    @Override\n    public void close() {\n        throw new IllegalStateException(\"Not supported for transaction scoped entity managers\");\n    }\n\n    @Override\n    public boolean isOpen() {\n        return true;\n    }\n\n    @Override\n    public Transaction getTransaction() {\n        throw new IllegalStateException(\"Not supported for JTA entity managers\");\n    }\n\n    @Override\n    public EntityManagerFactory getEntityManagerFactory() {\n        return sessionFactory;\n    }\n\n    @Override\n    public HibernateCriteriaBuilder getCriteriaBuilder() {\n        checkBlocking();\n        try (SessionResult emr = acquireSession()) {\n            return emr.session.getCriteriaBuilder();\n        }\n    }\n\n    @Override\n    public Metamodel getMetamodel() {\n        try (SessionResult emr = acquireSession()) {","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java#L609-L645","documentation":"TransactionScopedSession is Quarkus's JTA-backed wrapper for Hibernate Session. Because transaction management is delegated to the JTA/ArC transaction layer (via @Transactional or QuarkusTransaction), direct use of the JPA Transaction API is not meaningful, so getTransaction() unconditionally throws IllegalStateException. It signals an API misuse, not a transient failure.","triggerScenarios":"Calling session.getTransaction() (or em.getTransaction()) on a Session/EntityManager obtained from the 'TransactionScopedSession' CDI bean — i.e. any @Inject Session/EntityManager in Quarkus when JTA is the transaction type.","commonSituations":"Porting code written for resource-local JPA (e.g. Spring Data or plain Java SE Hibernate where em.getTransaction().begin() is normal) to Quarkus; helper/util classes that begin/commit transactions manually; tests copied from non-Quarkus Hibernate examples.","solutions":["Remove the getTransaction()/begin/commit/rollback calls and annotate the method (or class) with @Transactional so Quarkus manages the transaction","Use io.quarkus.narayana.jta.QuarkusTransaction.begin()/commit()/rollback() or QuarkusTransaction.requiring()/calling() for programmatic transaction control","If you truly need resource-local behavior, configure a persistence unit with transaction-type RESOURCE_LOCAL outside the JTA-managed session (rare; not the default Quarkus path)"],"exampleFix":"// before\nvoid save(User u) {\n    Transaction tx = session.getTransaction();\n    tx.begin();\n    session.persist(u);\n    tx.commit();\n}\n// after\n@Transactional\nvoid save(User u) {\n    session.persist(u);\n}","handlingStrategy":"validation","validationCode":"if (session instanceof TransactionScopedSession || session.isDefaultReadOnly()) { /* Quarkus JTA-managed session */ }\n// Simplest pre-check: never call getTransaction(); verify the bean was obtained via @Inject in Quarkus\nimport io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession;\nboolean jtaManaged = session instanceof TransactionScopedSession;\nif (jtaManaged) { /* use @Transactional or QuarkusTransaction instead */ }","typeGuard":"static boolean isJtaManagedSession(jakarta.persistence.EntityManager em) {\n    return !(em instanceof org.hibernate.Session s)\n        || em.unwrap(org.hibernate.Session.class) != null; // in Quarkus, assume JTA-managed\n}\n// practical guard:\nstatic boolean supportsLocalTransactions(jakarta.persistence.EntityManager em) {\n    try { em.getTransaction(); return true; }\n    catch (IllegalStateException | jakarta.persistence.PersistenceException e) { return false; }\n}","tryCatchPattern":"try {\n    Transaction tx = session.getTransaction();\n    tx.begin();\n} catch (IllegalStateException e) {\n    // JTA-managed in Quarkus: switch to @Transactional or QuarkusTransaction.begin()\n    throw new IllegalStateException(\"Use @Transactional instead of manual transactions\", e);\n}","preventionTips":["Never call getTransaction()/begin()/commit() on injected Session/EntityManager in Quarkus","Use @Transactional (annotation) or QuarkusTransaction (programmatic) for all transaction control","When porting resource-local JPA code, audit every em.getTransaction() call site","Keep transaction logic in service beans, not entities or utilities that get the raw session"],"tags":["jta","hibernate-orm","quarkus","transactions","api-misuse"],"backgroundTag":"jpa-transaction-not-supported","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}