apache/druid · error · IllegalStateException

Cannot allocate segment if not leader.

Error message

Cannot allocate segment if not leader.

What it means

SegmentAllocationQueue.add() is the entry point that queues a segment-allocation request for batched processing, but only the Overlord leader may process allocations. When the local isLeader flag is false, the node rejects the request with this ISE instead of queueing work it cannot complete. It protects against followers/duplicates accepting allocation duties.

Source

Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentAllocationQueue.java:217

    }
  }

  /**
   * Gets the number of batches currently in the queue.
   */
  public int size()
  {
    return processingQueue.size();
  }

  /**
   * Queues a SegmentAllocateRequest. The returned future may complete successfully
   * with a non-null value or with a non-null value.
   */
  public Future<SegmentIdWithShardSpec> add(SegmentAllocateRequest request)
  {
    if (!isLeader.get()) {
      throw new ISE("Cannot allocate segment if not leader.");
    } else if (!isEnabled()) {
      throw new ISE("Batched segment allocation is disabled.");
    }

    final AllocateRequestKey requestKey = new AllocateRequestKey(request);
    final AtomicReference<Future<SegmentIdWithShardSpec>> futureReference = new AtomicReference<>();

    // Possible race condition:
    // t1 -> new batch is added to queue or batch already exists in queue
    // t2 -> executor pops batch, processes all requests in it
    // t1 -> new request is added to dangling batch and is never picked up
    // Solution: Perform the following operations only inside keyToBatch.compute():
    // 1. Add or remove from map
    // 2. Add batch to queue
    // 3. Mark batch as started
    // 4. Update requests in batch
    keyToBatch.compute(requestKey, (key, existingBatch) -> {
      if (existingBatch == null || existingBatch.isStarted() || existingBatch.isFull()) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Verify tasks/actions are routed to the current Overlord leader (check druid.overlord.leaderSelector / coordinator console).
  2. Wait for or trigger Overlord leader election to complete, then retry the allocation (tasks retry automatically).
  3. Fix load-balancer or service-discovery config so standby Overlords do not receive task-action traffic.
  4. Check for ZooKeeper/leadership flapping in the cluster logs and stabilize the Overlord group.
Defensive patterns

Strategy: retry

Validate before calling

// Before issuing SEGMENT_ALLOCATE, confirm this Overlord is leader:
// GET /druid/indexer/v1/leader -> compare with the Overlord being called

Try / catch

try { future = queue.add(request); } catch (ISE e) { if (e.getMessage().contains("not leader")) { /* re-route to leader Overlord or wait for election and retry */ } else throw e; }

Prevention

When it happens

Trigger: Calling add() on a SegmentAllocationQueue hosted on a non-leader Overlord, or during a leadership transition where the isLeader AtomicBoolean has been flipped off (leader lost leadership) while tasks still route requests to this node.

Common situations: Middle managers/tasks hitting a standby Overlord due to stale service discovery; Overlord leadership failover mid-ingestion; split-horizon deployments where task routing points at the wrong Overlord.

Related errors


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