apache/druid · error · IllegalStateException
can't stop.
Error message
can't stop.
What it means
ConsulDruidNodeDiscoveryProvider.stop() throws this ISE when the lifecycle lock reports the component is not in a startable/stopped-appropriate state, i.e. stop() was called before start() or while a start is in progress. Druid components guard their lifecycle with LifecycleLock so stop/start happen exactly once in the right order.
Source
Thrown at extensions-contrib/consul-extensions/src/main/java/org/apache/druid/consul/discovery/ConsulDruidNodeDiscoveryProvider.java:155
LOGGER.info("Starting ConsulDruidNodeDiscoveryProvider");
// Single-threaded executor ensures listener callbacks execute in-order, preventing race conditions
listenerExecutor = Execs.scheduledSingleThreaded("ConsulDruidNodeDiscoveryProvider-ListenerExecutor");
LOGGER.info("Started ConsulDruidNodeDiscoveryProvider");
lifecycleLock.started();
}
finally {
lifecycleLock.exitStart();
}
}
@LifecycleStop
public void stop()
{
if (!lifecycleLock.canStop()) {
throw new ISE("can't stop.");
}
LOGGER.info("Stopping ConsulDruidNodeDiscoveryProvider");
for (NodeRoleWatcher watcher : nodeRoleWatchers.values()) {
watcher.stop();
}
nodeRoleWatchers.clear();
// Watcher threads must finish before shutting down listener executor to avoid RejectedExecutionException
try {
listenerExecutor.shutdown();
if (!listenerExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
LOGGER.warn("Listener executor did not terminate in time");
listenerExecutor.shutdownNow();
}
}
catch (InterruptedException e) {View on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure start() is invoked (and completes) before stop(); only call stop() after a successful start().
- Guard your shutdown code with lifecycleLock.awaitStopped()/state checks instead of calling stop() unconditionally.
- In tests, register the provider with a Lifecycle and stop the Lifecycle rather than calling stop() directly.
- Check for earlier exceptions during start() that prevented the lock from entering the started state.
Example fix
// before
provider.stop(); // throws if never started
// after
if (started) {
provider.stop();
started = false;
} Defensive patterns
Strategy: validation
Validate before calling
if (!started || stopping) { return; }
provider.stop(); Prevention
- Manage component lifecycle exclusively through a Druid Lifecycle instance.
- Never call stop() more than once; guard with an AtomicBoolean.
- Check for start() failures in logs before attempting shutdown.
When it happens
Trigger: Calling stop() before start() has ever succeeded, calling stop() twice, or racing stop() against a concurrent start() (canStop() returns false).
Common situations: Manual lifecycle manipulation in tests or embedded setups, a start() failure that left the lock in started=false, or double shutdown from both a Lifecycle handler and application shutdown hooks.
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/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/01c5c9658531b5d6.
Report an issue: GitHub.