{"record":{"id":"c861cc5ad7fd7f99","repo":"apache/druid","slug":"can-t-start-c861cc","errorCode":null,"errorMessage":"can't start.","messagePattern":"can't start\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions-core/kubernetes-extensions/src/main/java/org/apache/druid/k8s/discovery/K8sDruidLeaderSelector.java","lineNumber":134,"sourceCode":"  @Override\n  public boolean isLeader()\n  {\n    return leader;\n  }\n\n  @Override\n  public int localTerm()\n  {\n    return term;\n  }\n\n  @Override\n  public void registerListener(DruidLeaderSelector.Listener listener)\n  {\n    Preconditions.checkArgument(listener != null, \"listener is null.\");\n\n    if (!lifecycleLock.canStart()) {\n      throw new ISE(\"can't start.\");\n    }\n    try {\n      this.listener = listener;\n      startLeaderElector(leaderLatch);\n      lifecycleLock.started();\n    }\n    catch (Exception ex) {\n      throw new RuntimeException(ex);\n    }\n    finally {\n      lifecycleLock.exitStart();\n    }\n  }\n\n  @Override\n  public void unregisterListener()\n  {\n    if (!lifecycleLock.canStop()) {","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/kubernetes-extensions/src/main/java/org/apache/druid/k8s/discovery/K8sDruidLeaderSelector.java#L116-L152","documentation":"registerListener() guards startup with LifecycleLock.canStart(); if the selector is already started (or concurrently starting/stopping) the lock refuses and an IllegalStateException \"can't start.\" is thrown. Each K8sDruidLeaderSelector instance may only have its listener registered once.","triggerScenarios":"Calling registerListener twice on the same K8sDruidLeaderSelector instance, or calling it concurrently/unregisterListener racing it.","commonSituations":"Service wiring registering a listener both in init and on a reconfigure callback; tests reusing a selector instance across test methods; lifecycle races in overloaded/stop-start sequences.","solutions":["Register the listener exactly once per selector instance; create a new K8sDruidLeaderSelector if you need to restart.","Call unregisterListener() and wait for stop to complete before attempting registerListener again.","Guard the call site with isLeader()/state checks rather than relying on registerListener for idempotency.","Serialize lifecycle calls (no concurrent register/unregister from multiple threads)."],"exampleFix":"// before\nleaderSelector.registerListener(listener); // second call -> ISE\n// after: create fresh instance or check lifecycle\nif (!started) { leaderSelector.registerListener(listener); started = true; }","handlingStrategy":"type-guard","validationCode":"if (!lifecycleLock.canStart()) { /* skip duplicate registration or recreate selector */ }","typeGuard":"boolean isStartable(LeaderSelector s) {\n  try { return s.getCurrentLeader() != null || true; } catch (RuntimeException e) { return false; } // replace with state introspection\n}\n// practical guard: track registration locally\nAtomicBoolean registered = new AtomicBoolean(false);\nif (registered.compareAndSet(false, true)) selector.registerListener(listener);","tryCatchPattern":"try {\n  leaderSelector.registerListener(listener);\n} catch (ISE e) {\n  LOG.warn(\"Listener already registered or selector stopping; ignoring\");\n}","preventionTips":["Register the listener once per selector instance (e.g. in an init-once path).","Never call registerListener concurrently from multiple threads.","Unregister and wait before any re-registration; prefer new instances for restarts.","Avoid re-registering on config reload; reconfigure the listener instead."],"tags":["leader-election","lifecycle","illegal-state","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}