apache/druid · error · IllegalStateException

is not started

Error message

${className} is not started

What it means

SqlSegmentsMetadataManager throws this IllegalStateException from startPollingDatabasePeriodically() when the manager's periodic polling is requested but the manager lifecycle was never started via start(). Internally, the executor field (exec) is null, meaning start() was not called (or stop() already tore it down). It is a lifecycle-ordering guard: polling cannot be scheduled without the executor created during start().

Solutions

  1. Ensure the Druid Lifecycle (or startup injector) calls start() on SqlSegmentsMetadataManager before startPollingDatabasePeriodically().
  2. Check for double lifecycle management: some component may have called stop() before your startPollingDatabasePeriodically() call.
  3. In tests, call manager.start() in setup before enabling periodic polling.
  4. Wrap the call in a state check: only start polling when the manager reports started.

Example fix

// before
sqlSegmentsMetadataManager.startPollingDatabasePeriodically();
// after
sqlSegmentsMetadataManager.start(); // must precede polling start
sqlSegmentsMetadataManager.startPollingDatabasePeriodically();
Defensive patterns

Strategy: validation

Validate before calling

// before enabling polling
if (manager.isStarted()) { // check the manager's own state if exposed
  manager.startPollingDatabasePeriodically();
}

Type guard

boolean canPoll = manager != null && java.util.concurrent.atomic status-check: poll only when exec-backed lifecycle has started;

Try / catch

try {
  manager.startPollingDatabasePeriodically();
} catch (IllegalStateException e) {
  // manager not started: initialize lifecycle first or reschedule
}

Prevention

When it happens

Trigger: Calling startPollingDatabasePeriodically() before start() has been invoked on the manager, or after stop() released the polling executor (exec == null) while holding the startStopPollLock write lock.

Common situations: Coordinator/Historical node wiring where the SqlSegmentsMetadataManager is injected but its Lifecycle was never started; custom code or tests that call startPollingDatabasePeriodically() directly without the Druid lifecycle; calling polling start after a shutdown hook already stopped the manager.

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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/metadata/SqlSegmentsMetadataManager.java:291

    ReentrantReadWriteLock.WriteLock lock = startStopPollLock.writeLock();
    lock.lock();
    try {
      exec.shutdownNow();
      exec = null;
    }
    finally {
      lock.unlock();
    }
  }

  @Override
  public void startPollingDatabasePeriodically()
  {
    ReentrantReadWriteLock.WriteLock lock = startStopPollLock.writeLock();
    lock.lock();
    try {
      if (exec == null) {
        throw new IllegalStateException(getClass().getName() + " is not started");
      }
      if (isPollingDatabasePeriodically()) {
        return;
      }

      PeriodicDatabasePoll periodicDatabasePoll = new PeriodicDatabasePoll();
      latestDatabasePoll = periodicDatabasePoll;

      startPollingCount++;
      currentStartPollingOrder = startPollingCount;
      final long localStartOrder = currentStartPollingOrder;

      periodicPollTaskFuture = exec.scheduleWithFixedDelay(
          createPollTaskForStartOrder(localStartOrder, periodicDatabasePoll),
          0,
          periodicPollDelay.getMillis(),
          TimeUnit.MILLISECONDS
      );

View on GitHub (pinned to 9b90983fd2)