apache/druid · error · IllegalStateException

can't start

Error message

can't start

What it means

ConsulLeaderSelector.registerListener() throws this ISE when the lifecycle lock refuses the start, meaning the selector was already started (listener already registered) or is being stopped. registerListener is itself the 'start' of the leader-election machinery (session keeper and scheduled executors).

Source

Thrown at extensions-contrib/consul-extensions/src/main/java/org/apache/druid/consul/discovery/ConsulLeaderSelector.java:141

  @Override
  public boolean isLeader()
  {
    return leader.get();
  }

  @Override
  public int localTerm()
  {
    return term.get();
  }

  @Override
  public void registerListener(Listener listener)
  {
    Preconditions.checkArgument(listener != null, "listener is null");

    if (!lifecycleLock.canStart()) {
      throw new ISE("can't start");
    }

    try {
      this.listener = listener;
      this.executorService = Execs.scheduledSingleThreaded("ConsulLeaderSelector-%d");
      this.sessionKeeperService = Execs.scheduledSingleThreaded("ConsulSessionKeeper-%d");

      startLeaderElection();

      lifecycleLock.started();
    }
    catch (Exception ex) {
      throw new RuntimeException(ex);
    }
    finally {
      lifecycleLock.exitStart();
    }
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Register the listener exactly once, at service startup.
  2. Use a new ConsulLeaderSelector instance if you need to re-register after unregistering.
  3. Guard registration with a boolean/AtomicBoolean in the calling service.
  4. Ensure unregisterListener() is not concurrently executing when registerListener() is called.

Example fix

// before
leaderSelector.registerListener(listener);
...
leaderSelector.registerListener(listener); // ISE: can't start
// after
if (registered.compareAndSet(false, true)) {
  leaderSelector.registerListener(listener);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!registered.compareAndSet(false, true)) { return; }
leaderSelector.registerListener(listener);

Prevention

When it happens

Trigger: Calling registerListener() more than once on the same ConsulLeaderSelector, or calling it after unregisterListener() / during shutdown so canStart() returns false.

Common situations: Re-registering a leadership listener on hot reconfiguration, registering the same selector from two services, or registering after a stop during server teardown.

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/0d3562d27f6cec33. Report an issue: GitHub.