apache/druid · error · IllegalStateException
can't stop.
Error message
can't stop.
What it means
Thrown by CoordinatorPollingBasicAuthenticatorCacheManager.stop when lifecycleLock.canStop() returns false. stop() may only be called when the component is actually in a started state; calling stop before start, twice in a row, or concurrently fails this guard with an ISE. It signals an illegal lifecycle transition, not a shutdown problem per se.
Source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManager.java:150
catch (Throwable t) {
LOG.makeAlert(t, "Error occurred while polling for cachedUserMaps.").emit();
}
}
);
lifecycleLock.started();
LOG.info("Started CoordinatorPollingBasicAuthenticatorCacheManager.");
}
finally {
lifecycleLock.exitStart();
}
}
@LifecycleStop
public void stop()
{
if (!lifecycleLock.canStop()) {
throw new ISE("can't stop.");
}
LOG.info("CoordinatorPollingBasicAuthenticatorCacheManager is stopping.");
exec.shutdownNow();
LOG.info("CoordinatorPollingBasicAuthenticatorCacheManager is stopped.");
}
@Override
public void handleAuthenticatorUserMapUpdate(String authenticatorPrefix, byte[] serializedUserMap)
{
LOG.debug("Received user cache update for authenticator [%s].", authenticatorPrefix);
Preconditions.checkState(lifecycleLock.awaitStarted(1, TimeUnit.MILLISECONDS));
try {
cachedUserMaps.put(
authenticatorPrefix,
objectMapper.readValue(
serializedUserMap,
BasicAuthUtils.AUTHENTICATOR_USER_MAP_TYPE_REFERENCEView on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure stop() is only called after a successful start() on the same instance
- Make stop idempotent by tracking stopped state in the caller or fixing the lifecycle lock usage
- In tests, always start before stopping and stop once per lifecycle
- Wrap shutdown logic so it checks lifecycle state rather than assuming the manager is running
Example fix
// before
manager.stop(); manager.stop(); // second call throws
// after
if (running) { manager.stop(); running = false; } Defensive patterns
Strategy: try-catch
Validate before calling
boolean stopIfRunning(AtomicBoolean running, CoordinatorPollingBasicAuthenticatorCacheManager m) { if (!running.get()) return false; m.stop(); running.set(false); return true; } Try / catch
try { manager.stop(); } catch (ISE e) { LOG.info("stop ignored: manager not in started state"); } Prevention
- Pair every start() with exactly one stop()
- Never stop before a successful start()
- Use an AtomicBoolean to make stop idempotent at the call site
- Ensure shutdown hooks don't double-invoke lifecycle stop
When it happens
Trigger: stop() called before start(); stop() called twice; concurrent stop from two threads after the first already claimed the transition; failing to await completion of a prior stop lifecycle stage.
Common situations: Test code (e.g. test_stop_interruptsPollingThread) invoking stop out of order; shutdown hooks firing after an earlier stop; leadership loss handling that stops twice.
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/0fafa4fd788db4a3.
Report an issue: GitHub.