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

  1. Only call addLastShutdownTask with a non-null Runnable; guard at the call site.
  2. Return a no-op Runnable instead of null from task factories.
  3. 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

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


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