quarkusio/quarkus · error · IllegalStateException

Unable to destroy contextual instance of " + bean

Error message

Unable to destroy contextual instance of " + bean

What it means

InjectableContext.destroy(ContextState) iterates every contextual instance held in the state and calls destroy(bean) for each; if any bean's destruction throws an Exception, it is wrapped in an IllegalStateException('Unable to destroy contextual instance of ' + bean) with the original as cause. This signals that a @PreDestroy/@Disposes callback or custom destroy() failed while the context was shutting down.

Source

Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableContext.java:76

            return result;
        }
        return get(contextual, creationalContextFunction.apply(contextual));
    }

    /**
     * Destroy all contextual instances from the given state.
     * <p>
     * The default implementation is not optimized and does not guarantee proper sychronization. Implementations of this
     * interface are encouraged to provide an optimized implementation of this method.
     *
     * @param state
     */
    default void destroy(ContextState state) {
        for (InjectableBean<?> bean : state.getContextualInstances().keySet()) {
            try {
                destroy(bean);
            } catch (Exception e) {
                throw new IllegalStateException("Unable to destroy contextual instance of " + bean, e);
            }
        }
    }

    /**
     *
     * @return {@code true} if this context represents a normal scope
     */
    default boolean isNormal() {
        return getScope().isAnnotationPresent(NormalScope.class);
    }

    interface ContextState {

        /**
         * @return an immutable map of contextual instances
         */
        Map<InjectableBean<?>, Object> getContextualInstances();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Look at the cause chain to find which bean's destroy failed and fix that bean's @PreDestroy/@Disposes/destroy() logic to be idempotent and exception-safe.
  2. Guard resource cleanup in destroy callbacks with null/ordering checks and catch-and-log non-fatal cleanup errors.
  3. Ensure destroy callbacks don't depend on services already stopped during shutdown ordering.
  4. If the failing bean comes from an extension, report/upgrade that extension — its destroy logic is faulty.

Example fix

// before
@PreDestroy
void close() {
    client.close(); // throws if already closed
}

// after
@PreDestroy
void close() {
    if (client != null) {
        try {
            client.close();
        } catch (RuntimeException e) {
            log.warn("Client close failed", e);
        }
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

for (InjectableBean<?> bean : state.getContextualInstances().keySet()) {
    // pre-check: beans whose destroy may fail should log-and-continue via their own @PreDestroy guards
    Objects.requireNonNull(bean, "contextual instance must not be null");
}

Try / catch

try {
    context.destroy(state);
} catch (IllegalStateException e) {
    log.warn("Context cleanup failed", e.getCause()); // inspect the per-bean cause
}

Prevention

When it happens

Trigger: Destroying a custom context or a ContextState (e.g. at application shutdown, session end, or request termination) when one of the contained beans' destroy methods — or a @PreDestroy callback / @Disposes method — throws an exception.

Common situations: @PreDestroy code closing resources that are already closed or null due to ordering; destroy callbacks throwing on shutdown because a backing server/database is gone; buggy custom InjectableBean.destroy() implementations; resource cleanup failing during hot reload.

Related errors


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