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
- Check the manager's state before calling start(); only start from a stopped state.
- Call stop() and let it complete before calling start() again.
- 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
- Pair every start() with exactly one stop(); never call start() twice without stopping.
- In leadership-callback code, guard start()/stop() with state checks to tolerate duplicate events.
- Wait for stop() to return before issuing a new start().
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)