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

  1. Ensure stop() is only called after a successful start() and only once; rely on the Druid Lifecycle for shutdown ordering.
  2. Guard your shutdown code with a started flag or check lifecycle state before calling stop().
  3. In tests, do not reuse a stopped instance; build a new one for the next start/stop cycle.
  4. 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

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.