apache/druid · error · IllegalStateException

LookupCoordinatorManager can't start.

Error message

LookupCoordinatorManager can't start.

What it means

LookupCoordinatorManager.start() uses a lifecycle lock so it can only transition to started from the stopped state. If canStart() returns false, the manager is already started or stopping, so start() throws this IllegalStateException rather than creating a duplicate management loop.

Solutions

  1. Check the manager's state before calling start(); only start from a stopped state.
  2. Call stop() and let it complete before calling start() again.
  3. If driven by leadership callbacks, verify no duplicate leadership-lost/gained events are being processed.

Example fix

// before
lookupCoordinatorManager.start();
lookupCoordinatorManager.start(); // throws
// after
if (!lookupCoordinatorManager.started()) {
  lookupCoordinatorManager.start();
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Java caller:
if (manager.started()) {
  return; // already running, do not start again
}

Type guard

public static boolean canStart(LifecycleLock lock) {
  return lock.canStart(); // inspect state without mutating
}

Try / catch

try {
  manager.start();
} catch (IllegalStateException e) {
  if (e.getMessage().equals("LookupCoordinatorManager can't start.")) {
    LOG.debug("Already started or stopping; ignoring duplicate start");
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling start() twice without an intervening stop(); calling start() while a previous stop() is still in progress; leadership callbacks firing start() concurrently (guarded, but a second call still throws).

Common situations: Coordinator gaining leadership twice in quick succession; application code (or tests) invoking start() manually when the lifecycle already started it; not calling stop() before restart attempts.

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/8fd153e776126c8e. Report an issue: GitHub.

Appendix: source

Thrown at server/src/main/java/org/apache/druid/server/lookup/cache/LookupCoordinatorManager.java:379

  public boolean isStarted()
  {
    return lifecycleLock.isStarted();
  }

  @VisibleForTesting
  boolean awaitStarted(long waitTimeMs)
  {
    return lifecycleLock.awaitStarted(waitTimeMs, TimeUnit.MILLISECONDS);
  }

  // start() and stop() are synchronized so that they never run in parallel in case of ZK acting funny or druid bug and
  // coordinator becomes leader and drops leadership in quick succession.
  public void start()
  {
    synchronized (lifecycleLock) {
      if (!lifecycleLock.canStart()) {
        throw new ISE("LookupCoordinatorManager can't start.");
      }

      try {
        LOG.debug("Starting.");

        if (lookupNodeDiscovery == null) {
          lookupNodeDiscovery = new LookupNodeDiscovery(druidNodeDiscoveryProvider);
        }

        //first ensure that previous executorService from last cycle of start/stop has finished completely.
        //so that we don't have multiple live executorService instances lying around doing lookup management.
        if (executorService != null &&
            !executorService.awaitTermination(
                lookupCoordinatorManagerConfig.getHostTimeout().getMillis() * 10,
                TimeUnit.MILLISECONDS
            )) {
          throw new ISE("LookupCoordinatorManager executor from last start() hasn't finished. Failed to Start.");
        }

View on GitHub (pinned to 9b90983fd2)