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
- Register the listener exactly once, at service startup.
- Use a new ConsulLeaderSelector instance if you need to re-register after unregistering.
- Guard registration with a boolean/AtomicBoolean in the calling service.
- 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
- Register the listener once at service startup, never on reconfiguration.
- Unregister by discarding the selector and creating a fresh one if re-registration is needed.
- Ensure register/unregister are not called concurrently.
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.