apache/druid · error · IllegalStateException
can't stop.
Error message
can't stop.
What it means
LeaderElectorAsyncWrapper.close() throws this IllegalStateException when LifecycleLock.canStop() returns false - the elector was never started via run(), is already closed, or is mid-close. The close path cancels the election future and shuts down the executor, which only exist after a successful run().
Source
Thrown at extensions-core/kubernetes-extensions/src/main/java/org/apache/druid/k8s/discovery/LeaderElectorAsyncWrapper.java:100
}
catch (Throwable ex) {
LOGGER.error(ex, "Exception in K8s LeaderElector.run()");
}
}
}
));
lifecycleLock.started();
}
finally {
lifecycleLock.exitStart();
}
}
@Override
public void close()
{
if (!lifecycleLock.canStop()) {
throw new ISE("can't stop.");
}
try {
futureRef.get().cancel(true);
executor.shutdownNow();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
LOGGER.warn("Failed to terminate [%s] executor.", this.getClass().getSimpleName());
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
public String getCurrentLeader()
{
return k8sLeaderElector.getCurrentLeader();
}View on GitHub (pinned to 9b90983fd2)
Solutions
- Only close() after run() has been called successfully
- Guard close with try-catch of IllegalStateException if the start state is unknown
- Avoid double-close: don't both register with Lifecycle and close manually
- If close must be idempotent, check an internal 'started' flag before delegating
Example fix
// before
elector.close(); // ISE if run() never called
// after
if (started) {
elector.close();
started = false;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!electorRunning) { return; } Try / catch
try { elector.close(); } catch (IllegalStateException e) { /* never started or already closed */ } Prevention
- Close only after run() succeeded
- Track started state before closing
- Avoid registering the elector in Lifecycle AND closing it manually
When it happens
Trigger: Calling close() before run(); calling close() twice (double close / try-with-resources plus manual close); close() racing run(); run() previously failed leaving state stuck.
Common situations: Overlord shutdown where the elector failed to start; cleanup code closing all services unconditionally; wrapping an unstarted elector in try-with-resources.
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/73194911e0afd2f6.
Report an issue: GitHub.