apache/druid · error · IllegalStateException

can't start.

Error message

can't start.

What it means

LookupReferencesManager.start(), annotated @LifecycleStart, uses a LifecycleLock; if canStart() returns false (already started, stop in progress, or stop already completed), it throws IllegalStateException 'can't start.' This enforces that the lookup manager transitions through its lifecycle exactly once and in order.

Source

Thrown at server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java:152

      this.lookupSnapshotTaker = null;
    } else {
      this.lookupSnapshotTaker = new LookupSnapshotTaker(objectMapper, lookupConfig.getSnapshotWorkingDir());
    }
    this.coordinatorClient = coordinatorClient;
    this.lookupListeningAnnouncerConfig = lookupListeningAnnouncerConfig;
    this.lookupConfig = lookupConfig;
    this.testMode = testMode;
    this.lookupUpdateExecutorService = Execs.multiThreaded(
        lookupConfig.getNumLookupLoadingThreads(),
        "LookupExtractorFactoryContainerProvider-Update-%s"
    );
  }

  @LifecycleStart
  public void start() throws IOException
  {
    if (!lifecycleLock.canStart()) {
      throw new ISE("can't start.");
    }
    try {
      LOG.debug("LookupExtractorFactoryContainerProvider starting.");
      if (!Strings.isNullOrEmpty(lookupConfig.getSnapshotWorkingDir())) {
        FileUtils.mkdirp(new File(lookupConfig.getSnapshotWorkingDir()));
      }
      loadLookupsAndInitStateRef();
      if (!testMode) {
        mainThread = Execs.makeThread(
            "LookupExtractorFactoryContainerProvider-MainThread",
            () -> {
              try {
                if (!lifecycleLock.awaitStarted()) {
                  LOG.error("Lifecycle not started, lookup update notices will not be handled.");
                  return;
                }

                while (!Thread.interrupted() && lifecycleLock.awaitStarted(1, TimeUnit.MILLISECONDS)) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Ensure start() is called exactly once per LookupReferencesManager instance via the Druid Lifecycle.
  2. Check logs/stack trace for a prior stop() call that invalidated the lifecycle lock.
  3. In tests, construct a fresh LookupReferencesManager per lifecycle cycle rather than reusing instances.
  4. Avoid calling start() from multiple threads; delegate to a single lifecycle coordinator.

Example fix

// before
manager.stop();
manager.start(); // ISE: can't start.
// after
LookupReferencesManager manager = new LookupReferencesManager(...); // fresh instance
manager.start();
Defensive patterns

Strategy: validation

Validate before calling

// call start() exactly once, e.g.
private final AtomicBoolean started = new AtomicBoolean(false);
if (started.compareAndSet(false, true)) { manager.start(); }

Try / catch

try {
  manager.start();
} catch (IllegalStateException e) {
  // already started or stopped: treat as idempotent no-op or recreate instance
}

Prevention

When it happens

Trigger: Calling start() after the manager is already started; calling start() concurrently with or after stop(); lifecycle mis-wiring where a second component attempts to start the same instance.

Common situations: Double registration of LookupReferencesManager in a custom lifecycle; unit tests starting/stopping repeatedly without resetting; race between node shutdown and startup 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/006a26da68737a23. Report an issue: GitHub.