quarkusio/quarkus · error · IllegalStateException

Persistence unit is closed

Error message

Persistence unit is closed

What it means

Thrown by JPAConfig's lazy EntityManagerFactory holder after the persistence unit has been explicitly closed via JPAConfig.stop(). Once closed, the holder refuses to re-bootstrap the EMF, signaling the application is shutting down or the PU was torn down. It guards against recreating EMFs during shutdown (e.g. from a shutdown hook, async task, or scheduled job still running).

Source

Thrown at extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/JPAConfig.java:175

    }

    static final class LazyPersistenceUnit {

        private final String name;
        private final boolean isReactive;
        private volatile EntityManagerFactory value;
        private volatile boolean closed = false;

        LazyPersistenceUnit(String name, boolean isReactive) {
            this.name = name;
            this.isReactive = isReactive;
        }

        EntityManagerFactory get() {
            if (value == null) {
                synchronized (this) {
                    if (closed) {
                        throw new IllegalStateException("Persistence unit is closed");
                    }
                    if (value == null) {
                        value = Persistence.createEntityManagerFactory(name,
                                Collections.singletonMap(IS_REACTIVE_KEY, isReactive));
                    }
                }
            }
            return value;
        }

        public synchronized void close() {
            closed = true;
            EntityManagerFactory emf = this.value;
            this.value = null;
            if (emf != null) {
                emf.close();
            }
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Stop using the persistence unit after shutdown begins; shut down your executors/schedulers before Quarkus terminates.
  2. Check application state: if this happens at shutdown, treat it as expected and drain tasks gracefully.
  3. If it happens mid-run, audit for manual calls to JPAConfig.stop()/close in your code or tests.

Example fix

// before
executor.submit(() -> emf.createEntityManager()); // may run after shutdown
// after
executor.shutdown();
executor.awaitTermination(30, TimeUnit.SECONDS); // drain before PU closes
Defensive patterns

Strategy: try-catch

Validate before calling

// Check quarkus runtime status before submitting background JPA work
if (!Quarkus.isStarted() || Quarkus.isStopping()) {
    return; // skip DB work during shutdown
}

Try / catch

try {
    EntityManager em = emf.createEntityManager();
    // ...
} catch (IllegalStateException e) {
    if ("Persistence unit is closed".equals(e.getMessage())) {
        log.info("Skipping task: application is shutting down");
    } else { throw e; }
}

Prevention

When it happens

Trigger: Code calls getEntityManagerFactory()/createEntityManager after the application has begun shutdown (JPAConfig.stop invoked); a background thread, timer, or Dev UI request races application termination; closing and then re-accessing the PU in a test.

Common situations: Quartz/Scheduled jobs firing during graceful shutdown; long-running streams writing to the DB while Quarkus stops; tests that stop JPAConfig mid-test then keep using entities.

Related errors


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