apache/druid · error · RuntimeException (Druid RE)

Failed to get current leader for [%s]

Error message

Failed  to get current leader for [%s]

What it means

Wraps a Kubernetes ApiException thrown while reading the holder identity of the leader-election lock (a CoordinationV1Api Lease/ConfigMap lock). The elector could not fetch the current lock object, so the current leader is unknown.

Source

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

    LeaderElectionConfig leaderElectionConfig =
        new LeaderElectionConfig(
            lock,
            Duration.ofMillis(discoveryConfig.getLeaseDuration().getMillis()),
            Duration.ofMillis(discoveryConfig.getRenewDeadline().getMillis()),
            Duration.ofMillis(discoveryConfig.getRetryPeriod().getMillis())
        );
    LeaderElector leaderElector = new LeaderElector(leaderElectionConfig);

    return new K8sLeaderElector()
    {
      @Override
      public String getCurrentLeader()
      {
        try {
          return lock.get().getHolderIdentity();
        }
        catch (ApiException ex) {
          throw new RE(ex, "Failed  to get current leader for [%s]", lockResourceName);
        }
      }

      @Override
      public void run(Runnable startLeadingHook, Runnable stopLeadingHook)
      {
        leaderElector.run(startLeadingHook, stopLeadingHook);
      }
    };
  }

  private Lock createLock(String candidateId, String namespace, String lockResourceName, ApiClient k8sApiClient)
  {
    return new ConfigMapLock(
        namespace,
        lockResourceName,
        candidateId,
        k8sApiClient

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Grant the service account get on the lock resource (leases in coordination.k8s.io for the namespace).
  2. Verify the lock resource name and namespace in druid.k8s leader-election config exist (kubectl get lease <name> -n <ns>).
  3. Fix auth (valid service-account token) if the code is 401.
  4. Retry on transient errors; the message identifies which lock failed via lockResourceName.

Example fix

// before: kubectl auth can-i get leases.coordination.k8s.io -n druid => no
// after: grant RBAC
kubectl create role druid-leader --verb=get,list,watch --resource=leases.coordination.k8s.io -n druid
kubectl create rolebinding druid-leader --role=druid-leader --serviceaccount=druid:druid-sa -n druid
Defensive patterns

Strategy: retry

Validate before calling

// before electing: check lock access
kubectl auth can-i get leases.coordination.k8s.io -n <namespace>  # must be yes
kubectl get lease <lockResourceName> -n <namespace>              # must exist

Try / catch

try {
  String leader = elector.getCurrentLeader();
} catch (RE e) {
  if (e.getCause() instanceof ApiException && ((ApiException) e.getCause()).getCode() == 404) {
    return null; // no leader yet
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getCurrentLeader on the leader elector created by DefaultK8sLeaderElectorFactory when the underlying lock.get() request to the K8s API fails (403 RBAC, 404 missing lock object, 401 auth, network error).

Common situations: Service account missing get permission on the Lease/configmap used as lock; lockResourceName/namespace misconfigured; lock object deleted; transient API server errors.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/fd30b9568cd449f2. Report an issue: GitHub.