apache/druid · error · IllegalStateException

can't stop.

Error message

can't stop.

What it means

Thrown by CoordinatorBasicAuthenticatorMetadataStorageUpdater.stop when lifecycleLock.canStop() returns false. stop() is only legal from the started state; calling it before start, twice, or concurrently triggers this ISE. The method would otherwise mark the updater stopped so subsequent user-map updates are rejected.

Source

Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/updater/CoordinatorBasicAuthenticatorMetadataStorageUpdater.java:213

                LOG.makeAlert(t, "Error occurred while polling for cachedUserMaps.").emit();
              }
              return ScheduledExecutors.Signal.REPEAT;
            }
          }
      );

      lifecycleLock.started();
    }
    finally {
      lifecycleLock.exitStart();
    }
  }

  @LifecycleStop
  public void stop()
  {
    if (!lifecycleLock.canStop()) {
      throw new ISE("can't stop.");
    }

    LOG.info("CoordinatorBasicAuthenticatorMetadataStorageUpdater is stopping.");
    stopped = true;
    LOG.info("CoordinatorBasicAuthenticatorMetadataStorageUpdater is stopped.");
  }

  @Override
  public void createUser(String prefix, String userName)
  {
    Preconditions.checkState(lifecycleLock.awaitStarted(1, TimeUnit.MILLISECONDS));
    createUserInternal(prefix, userName);
  }

  @Override
  public void deleteUser(String prefix, String userName)
  {
    Preconditions.checkState(lifecycleLock.awaitStarted(1, TimeUnit.MILLISECONDS));

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Track started/stopped in the caller and skip redundant stop calls
  2. Ensure the lifecycle lock usage matches Druid conventions (canStop/stopInState)
  3. In tests, pair every start with exactly one stop in teardown
  4. If the updater is already stopped, treat further stops as no-ops

Example fix

// before
updater.stop(); updater.stop(); // second call throws
// after
if (started) { updater.stop(); started = false; }
Defensive patterns

Strategy: try-catch

Validate before calling

if (!updaterStarted.get()) { return; } // only stop after successful start
updater.stop(); updaterStarted.set(false);

Try / catch

try { updater.stop(); } catch (ISE e) { LOG.info("stop ignored: updater not started"); }

Prevention

When it happens

Trigger: stop() invoked without a prior successful start(); duplicate stop during shutdown; two threads racing to stop; lifecycle framework emitting stop events twice for one start.

Common situations: JVM shutdown hooks plus explicit lifecycle stop; test teardown stopping an already-stopped updater; leadership revocation handlers firing redundantly.

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