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.

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)

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.