{"record":{"id":"a0c04f0e24dd2c6f","repo":"quarkusio/quarkus","slug":"extension-passed-an-invalid-last-shutdown-handler","errorCode":null,"errorMessage":"Extension passed an invalid last shutdown handler","messagePattern":"Extension passed an invalid last shutdown handler","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/runtime/src/main/java/io/quarkus/runtime/StartupContext.java","lineNumber":46,"sourceCode":"    private String currentBuildStepName;\n\n    public StartupContext() {\n        ShutdownContext shutdownContext = new ShutdownContext() {\n            @Override\n            public void addShutdownTask(Runnable runnable) {\n                if (runnable != null) {\n                    shutdownTasks.addFirst(runnable);\n                } else {\n                    throw new IllegalArgumentException(\"Extension passed an invalid shutdown handler\");\n                }\n            }\n\n            @Override\n            public void addLastShutdownTask(Runnable runnable) {\n                if (runnable != null) {\n                    lastShutdownTasks.addFirst(runnable);\n                } else {\n                    throw new IllegalArgumentException(\"Extension passed an invalid last shutdown handler\");\n                }\n            }\n        };\n        values.put(ShutdownContext.class.getName(), shutdownContext);\n        values.put(RAW_COMMAND_LINE_ARGS, new Supplier<String[]>() {\n            @Override\n            public String[] get() {\n                if (commandLineArgs == null) {\n                    throw new RuntimeException(\"Command line arguments not available during static init\");\n                }\n                return commandLineArgs;\n            }\n        });\n    }\n\n    public void putValue(String name, Object value) {\n        values.put(name, value);\n    }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/runtime/src/main/java/io/quarkus/runtime/StartupContext.java#L28-L64","documentation":"StartupContext's ShutdownContext.addLastShutdownTask throws IllegalArgumentException when a null Runnable is passed. Last shutdown tasks run after all regular shutdown tasks; a null task is invalid and indicates an extension programming error.","triggerScenarios":"Calling shutdownContext.addLastShutdownTask(null), usually from a recorder whose task construction returned null when an optional component is absent.","commonSituations":"Extensions that register final cleanup (e.g. closing executors) conditionally and pass null when disabled.","solutions":["Only call addLastShutdownTask with a non-null Runnable; guard at the call site.","Return a no-op Runnable instead of null from task factories.","Identify the offending extension from the startup stack trace and fix its recorder."],"exampleFix":"// before\nshutdownContext.addLastShutdownTask(finalCleanup == null ? null : finalCleanup);\n// after\nif (finalCleanup != null) { shutdownContext.addLastShutdownTask(finalCleanup); }","handlingStrategy":"validation","validationCode":"if (task != null) { shutdownContext.addLastShutdownTask(task); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard last shutdown task registration for disabled features","Prefer no-op Runnables over null from task suppliers","Review extension recorders that build tasks conditionally"],"tags":["quarkus","shutdown","null-argument","extension"],"backgroundTag":"null-argument","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}