apache/druid · warning · IllegalStateException

can't stop.

Error message

can't stop.

What it means

unregisterListener() requires LifecycleLock.canStop(); if the selector was never started, is already stopped, or is mid-startup, an IllegalStateException "can't stop." is thrown. It enforces balanced start/stop of the leader elector.

Source

Thrown at extensions-core/kubernetes-extensions/src/main/java/org/apache/druid/k8s/discovery/K8sDruidLeaderSelector.java:153

    }
    try {
      this.listener = listener;
      startLeaderElector(leaderLatch);
      lifecycleLock.started();
    }
    catch (Exception ex) {
      throw new RuntimeException(ex);
    }
    finally {
      lifecycleLock.exitStart();
    }
  }

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

    closeLeaderLatchQuietly();
  }

  private void closeLeaderLatchQuietly()
  {
    CloseableUtils.closeAndSuppressExceptions(
        leaderLatch,
        e -> LOGGER.warn("Exception caught while cleaning up leader latch")
    );
  }
}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Track whether the selector is started; only call unregisterListener after a successful registerListener.
  2. Make cleanup idempotent by catching/ignoring ISE in shutdown paths.
  3. Wait for any in-flight registerListener to finish before stopping.
  4. If a start failed, recreate the selector rather than stopping it.

Example fix

// before
@Override public void shutdown() { leaderSelector.unregisterListener(); } // throws if never started
// after
@Override public void shutdown() { try { leaderSelector.unregisterListener(); } catch (IllegalStateException e) { LOG.debug("not started"); } }
Defensive patterns

Strategy: try-catch

Validate before calling

// only stop if you started
boolean started = false;
// at register: started = true;  at unregister: if (!started) return;

Try / catch

try {
  leaderSelector.unregisterListener();
} catch (IllegalStateException e) {
  LOG.debug(e, "Selector was not started; nothing to stop");
}

Prevention

When it happens

Trigger: Calling unregisterListener on a K8sDruidLeaderSelector that never had registerListener succeed, or calling it twice / concurrently with a start in progress.

Common situations: Shutdown hooks firing after an earlier stop; cleanup paths running when listener registration failed earlier; double-stop in tests.

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