quarkusio/quarkus · error · IllegalArgumentException
Extension passed an invalid last shutdown handler
Error message
Extension passed an invalid last shutdown handler
What it means
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.
Source
Thrown at core/runtime/src/main/java/io/quarkus/runtime/StartupContext.java:46
private String currentBuildStepName;
public StartupContext() {
ShutdownContext shutdownContext = new ShutdownContext() {
@Override
public void addShutdownTask(Runnable runnable) {
if (runnable != null) {
shutdownTasks.addFirst(runnable);
} else {
throw new IllegalArgumentException("Extension passed an invalid shutdown handler");
}
}
@Override
public void addLastShutdownTask(Runnable runnable) {
if (runnable != null) {
lastShutdownTasks.addFirst(runnable);
} else {
throw new IllegalArgumentException("Extension passed an invalid last shutdown handler");
}
}
};
values.put(ShutdownContext.class.getName(), shutdownContext);
values.put(RAW_COMMAND_LINE_ARGS, new Supplier<String[]>() {
@Override
public String[] get() {
if (commandLineArgs == null) {
throw new RuntimeException("Command line arguments not available during static init");
}
return commandLineArgs;
}
});
}
public void putValue(String name, Object value) {
values.put(name, value);
}View on GitHub (pinned to e1c734241f)
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.
Example fix
// before
shutdownContext.addLastShutdownTask(finalCleanup == null ? null : finalCleanup);
// after
if (finalCleanup != null) { shutdownContext.addLastShutdownTask(finalCleanup); } Defensive patterns
Strategy: validation
Validate before calling
if (task != null) { shutdownContext.addLastShutdownTask(task); } Prevention
- Guard last shutdown task registration for disabled features
- Prefer no-op Runnables over null from task suppliers
- Review extension recorders that build tasks conditionally
When it happens
Trigger: Calling shutdownContext.addLastShutdownTask(null), usually from a recorder whose task construction returned null when an optional component is absent.
Common situations: Extensions that register final cleanup (e.g. closing executors) conditionally and pass null when disabled.
Related errors
- Extension passed an invalid shutdown handler
- Failed to load steps from %s
- A build step must be a non-static method: %s
- java.lang.InterruptedException (wrapped)
- The application is stopping
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/a0c04f0e24dd2c6f.
Report an issue: GitHub.