{"record":{"id":"883e2fd7e7b76963","repo":"quarkusio/quarkus","slug":"unable-to-destroy-contextual-instance-of-bean","errorCode":null,"errorMessage":"Unable to destroy contextual instance of \" + bean","messagePattern":"Unable to destroy contextual instance of \" \\+ bean","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableContext.java","lineNumber":76,"sourceCode":"            return result;\n        }\n        return get(contextual, creationalContextFunction.apply(contextual));\n    }\n\n    /**\n     * Destroy all contextual instances from the given state.\n     * <p>\n     * The default implementation is not optimized and does not guarantee proper sychronization. Implementations of this\n     * interface are encouraged to provide an optimized implementation of this method.\n     *\n     * @param state\n     */\n    default void destroy(ContextState state) {\n        for (InjectableBean<?> bean : state.getContextualInstances().keySet()) {\n            try {\n                destroy(bean);\n            } catch (Exception e) {\n                throw new IllegalStateException(\"Unable to destroy contextual instance of \" + bean, e);\n            }\n        }\n    }\n\n    /**\n     *\n     * @return {@code true} if this context represents a normal scope\n     */\n    default boolean isNormal() {\n        return getScope().isAnnotationPresent(NormalScope.class);\n    }\n\n    interface ContextState {\n\n        /**\n         * @return an immutable map of contextual instances\n         */\n        Map<InjectableBean<?>, Object> getContextualInstances();","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableContext.java#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"@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.","solutions":["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.","Guard resource cleanup in destroy callbacks with null/ordering checks and catch-and-log non-fatal cleanup errors.","Ensure destroy callbacks don't depend on services already stopped during shutdown ordering.","If the failing bean comes from an extension, report/upgrade that extension — its destroy logic is faulty."],"exampleFix":"// before\n@PreDestroy\nvoid close() {\n    client.close(); // throws if already closed\n}\n\n// after\n@PreDestroy\nvoid close() {\n    if (client != null) {\n        try {\n            client.close();\n        } catch (RuntimeException e) {\n            log.warn(\"Client close failed\", e);\n        }\n    }\n}","handlingStrategy":"try-catch","validationCode":"for (InjectableBean<?> bean : state.getContextualInstances().keySet()) {\n    // pre-check: beans whose destroy may fail should log-and-continue via their own @PreDestroy guards\n    Objects.requireNonNull(bean, \"contextual instance must not be null\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    context.destroy(state);\n} catch (IllegalStateException e) {\n    log.warn(\"Context cleanup failed\", e.getCause()); // inspect the per-bean cause\n}","preventionTips":["Make every @PreDestroy/@Disposes/destroy() idempotent and non-throwing (catch and log cleanup failures).","Avoid depending on already-stopped services inside destroy callbacks.","Test application shutdown paths, especially with containers/databases stopping first."],"tags":["arc","cdi","context","lifecycle","shutdown","quarkus"],"backgroundTag":"contextual-instance-destroy-failed","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"}