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
- Register shutdown hooks during normal startup, not from shutdown-triggered callbacks.
- Check ShutdownHookManager.hasShutdownHookBeenRegistered()/isShutdownInProgress before registering and skip if already in progress.
- 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
- Register hooks only during startup/bean initialization.
- Do not register hooks from shutdown callbacks or other hooks.
- Make cleanup logic callable both as a hook and inline.
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
- Shutdown in progress, cannot remove a shutdownHook
- shutdownHook cannot be NULL
- Executor is shutdown!
- Timer already shutdown
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)