quarkusio/quarkus · error · IllegalStateException

Not supported for transaction scoped entity managers

Error message

Not supported for transaction scoped entity managers

What it means

TransactionScopedSession.close() always throws IllegalStateException because the lifecycle of a transaction-scoped EntityManager is owned by Quarkus/ArC: a new session is acquired per transaction and closed automatically when the transaction ends. Application code must never close it manually, so close() is intentionally unsupported.

Solutions

  1. Delete the em.close() call — Quarkus closes the session automatically when the transaction or request scope ends
  2. Use @Inject EntityManager and let CDI handle lifecycle; keep methods @Transactional for writes
  3. If you truly need manual lifecycle, switch to an application-scoped (extended) EntityManager via a producer using PersistenceUnit extension semantics, but avoid closing injected EMs
  4. Unwrap only for operations: em.unwrap(Session.class) — do not close the result

Example fix

// before
@Transactional
public void save(MyEntity e) {
    em.persist(e);
    em.close(); // throws IllegalStateException
}
// after
@Transactional
public void save(MyEntity e) {
    em.persist(e); // Quarkus closes the session itself
}
Defensive patterns

Strategy: type-guard

Validate before calling

// never close an injected, transaction-scoped EntityManager
if (em.isJoinedToTransaction() || em.isOpen()) {
    // safe to use, NOT safe to close
    em.persist(entity); // do NOT call em.close()
}

Type guard

boolean isContainerManaged(EntityManager em) {
    // container-managed Quarkus EMs are @TransactionScoped and close() is unsupported
    return em != null && em.isOpen()
        && CDI.current().select(EntityManager.class).stream().anyMatch(em::equals);
}
// guard: only close EMs you created yourself from an EntityManagerFactory

Try / catch

try {
    em.close();
} catch (IllegalStateException e) {
    // container-managed EM: remove the close call; Quarkus manages lifecycle
    log.debug("Skipping close of transaction-scoped EntityManager", e);
}

Prevention

When it happens

Trigger: Calling em.close() (or session.close()) on an injected, transaction-scoped EntityManager, typically copied from Java SE/Java EE code that managed its own EntityManagerFactory.

Common situations: Porting a DAO from a plain JPA app with emf.createEntityManager()/em.close(); cleanup code in @PreDestroy or finally blocks closing the injected EM; over-aggressive resource cleanup added during a refactor.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/ec03a8b49bded13c. Report an issue: GitHub.

Appendix: source

Thrown at extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java:617

        if (cls.isAssignableFrom(Session.class)) {
            return (T) this;
        }
        checkBlocking();
        try (SessionResult emr = acquireSession()) {
            return emr.session.unwrap(cls);
        }
    }

    @Override
    public Object getDelegate() {
        try (SessionResult emr = acquireSession()) {
            return emr.session.getDelegate();
        }
    }

    @Override
    public void close() {
        throw new IllegalStateException("Not supported for transaction scoped entity managers");
    }

    @Override
    public boolean isOpen() {
        return true;
    }

    @Override
    public Transaction getTransaction() {
        throw new IllegalStateException("Not supported for JTA entity managers");
    }

    @Override
    public EntityManagerFactory getEntityManagerFactory() {
        return sessionFactory;
    }

    @Override

View on GitHub (pinned to e1c734241f)