apache/shenyu · error · IllegalStateException

Shutdown in progress, cannot add a shutdownHook

Error message

Shutdown in progress, cannot add a shutdownHook

What it means

addShutdownHook also rejects registration once shutdown has begun: the manager flips an atomic `shutdownInProgress` flag when hooks start executing, and adding new hooks then is unsafe (they would never run or race the shutdown), so an IllegalStateException is thrown.

Solutions

  1. Register shutdown hooks during normal startup, not from shutdown-triggered callbacks.
  2. Check ShutdownHookManager.hasShutdownHookBeenRegistered()/isShutdownInProgress before registering and skip if already in progress.
  3. Make the cleanup run inline instead of as a hook when called during shutdown.

Example fix

// before
manager.addShutdownHook(client::close); // can run during shutdown
// after
if (!manager.isShutdownInProgress()) {
    manager.addShutdownHook(client::close);
} else {
    client.close();
}
Defensive patterns

Strategy: validation

Validate before calling

if (manager.isShutdownInProgress()) {
    // run inline instead of registering
    hook.run();
} else {
    manager.addShutdownHook(hook);
}

Try / catch

try {
    manager.addShutdownHook(hook);
} catch (IllegalStateException e) {
    LOGGER.warn("shutdown already started, running hook inline");
    hook.run();
}

Prevention

When it happens

Trigger: Calling addShutdownHook after JVM shutdown started running hooks — e.g. an async task, Spring context close callback, or connection-close path that lazily registers a hook while the application is exiting.

Common situations: Late resource cleanup triggered by a shutdown of another component; tests shutting down one context while another lazily registers; retry logic that re-registers hooks during exit.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/0b2af9a248ca0a7a. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/shutdown/ShutdownHookManager.java:105

        list.sort((o1, o2) -> o2.priority - o1.priority);
        List<Runnable> ordered = new ArrayList<>();
        list.forEach(entry -> ordered.add(entry.hook));
        return ordered;
    }

    /**
     * Adds a shutdownHook with default priority zero, the higher the priority
     * the earlier will run. ShutdownHooks with same priority run
     * in a non-deterministic order.
     *
     * @param shutdownHook shutdownHook <code>Runnable</code>
     */
    public void addShutdownHook(final Runnable shutdownHook) {
        if (Objects.isNull(shutdownHook)) {
            throw new IllegalArgumentException("shutdownHook cannot be NULL");
        }
        if (shutdownInProgress.get()) {
            throw new IllegalStateException("Shutdown in progress, cannot add a shutdownHook");
        }
        hooks.add(new HookEntry(shutdownHook, 0));
    }

    /**
     * Adds a shutdownHook with a priority, the higher the priority
     * the earlier will run. ShutdownHooks with same priority run
     * in a non-deterministic order.
     *
     * @param shutdownHook shutdownHook <code>Runnable</code>
     * @param priority     priority of the shutdownHook.
     */
    public void addShutdownHook(final Runnable shutdownHook, final int priority) {
        if (Objects.isNull(shutdownHook)) {
            throw new IllegalArgumentException("shutdownHook cannot be NULL");
        }
        if (shutdownInProgress.get()) {
            throw new IllegalStateException("Shutdown in progress, cannot add a shutdownHook");

View on GitHub (pinned to 567142e072)