apache/druid · error · IllegalStateException
can't stop.
Error message
can't stop.
What it means
LookupReferencesManager.stop(), annotated @LifecycleStop, throws IllegalStateException 'can't stop.' when lifecycleLock.canStop() is false — i.e., the manager was never started, is still starting, or was already stopped. The lock guarantees start/stop pairs are ordered and single-shot.
Source
Thrown at server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java:237
LOG.error(ex, "Exception occurred while handling lookup notice [%s].", notice);
LOG.makeAlert("Exception occurred while handling lookup notice, with message [%s].", ex.getMessage()).emit();
}
}
takeSnapshot(lookupMap);
ImmutableMap<String, LookupExtractorFactoryContainer> immutableLookupMap = ImmutableMap.copyOf(lookupMap);
atomicallyUpdateStateRef(
oldState -> new LookupUpdateState(immutableLookupMap, oldState.pendingNotices, ImmutableList.of())
);
}
@LifecycleStop
public void stop()
{
if (!lifecycleLock.canStop()) {
throw new ISE("can't stop.");
}
LOG.debug("LookupExtractorFactoryContainerProvider is stopping.");
if (!testMode) {
mainThread.interrupt();
try {
mainThread.join();
}
catch (InterruptedException ex) {
throw new ISE("failed to stop, mainThread couldn't finish.");
}
}
for (Map.Entry<String, LookupExtractorFactoryContainer> e : stateRef.get().lookupMap.entrySet()) {
try {
if (e.getValue().getLookupExtractorFactory().close()) {View on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure stop() is only called after a successful start() and only once; rely on the Druid Lifecycle for shutdown ordering.
- Guard your shutdown code with a started flag or check lifecycle state before calling stop().
- In tests, do not reuse a stopped instance; build a new one for the next start/stop cycle.
- If stop races during JVM shutdown, catch/ignore the IllegalStateException since teardown is already in progress.
Example fix
// before
manager.stop();
manager.stop(); // ISE: can't stop.
// after
if (!stopped) {
manager.stop();
stopped = true;
} Defensive patterns
Strategy: validation
Validate before calling
// only stop if previously started and not already stopped
if (started && !stopped) { manager.stop(); stopped = true; } Try / catch
try {
manager.stop();
} catch (IllegalStateException e) {
// not started or already stopped: safe to ignore during shutdown
} Prevention
- Pair every start() with exactly one stop()
- Route shutdown through the Druid Lifecycle rather than ad-hoc calls
- Make stop() idempotent in caller code with a flag
- In tests, recreate the manager instead of restarting it
When it happens
Trigger: Calling stop() before start() completed (or at all), calling stop() twice, or a shutdown hook racing with another component that already stopped the manager.
Common situations: Service shutdown ordering issues in embedded/test setups; tests (like testRealModeWithMainThread) that stop the manager then attempt a second stop; graceful-shutdown hooks firing twice.
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/bbb8aaa43acb76f4.
Report an issue: GitHub.