apache/druid · error · IndexOutOfBoundsException

List is full with elements.

Error message

List is full with %d elements.

What it means

ByteBufferIntList has a fixed capacity of maxElements ints in its backing buffer. add() throws IndexOutOfBoundsException when the list already holds maxElements, because a fixed-size off-heap list cannot grow.

Solutions

  1. Pre-size maxElements based on actual/estimated cardinality with headroom
  2. Check numElements == maxElements before add(), or use a growable structure
  3. Create a new larger ByteBufferIntList and copy when nearing capacity
  4. Verify no double-adding due to concurrent/merged iteration

Example fix

// before
list.add(val); // may throw when full
// after
if (list.numElements() >= list.maxElements()) {
  list = growList(list, list.maxElements() * 2);
}
list.add(val);
Defensive patterns

Strategy: validation

Validate before calling

if (list.size() >= list.maxElements()) { list = grow(list); }

Type guard

boolean canAdd(ByteBufferIntList l) { return l.numElements() < l.maxElements(); }

Try / catch

try { list.add(val); } catch (IndexOutOfBoundsException e) { if (e.getMessage().contains("List is full")) { list = growAndRetry(val); } }

Prevention

When it happens

Trigger: Calling add() more than maxElements times — e.g. appending more dictionary IDs/bitmap rows than were pre-sized during a groupBy merge operation where the element count estimate was exceeded.

Common situations: Underestimating cardinality of values merged into merge buffer; concurrent adds without synchronization; reused list instance across merges without resetting maxElements.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferIntList.java:57

  {
    this.buffer = buffer;
    this.maxElements = maxElements;
    this.numElements = 0;
    this.maxMergeBufferUsedBytes = 0;

    if (buffer.capacity() < (maxElements * Integer.BYTES)) {
      throw new IAE(
          "buffer for list is too small, was [%s] bytes, but need [%s] bytes.",
          buffer.capacity(),
          maxElements * Integer.BYTES
      );
    }
  }

  public void add(int val)
  {
    if (numElements == maxElements) {
      throw new IndexOutOfBoundsException(StringUtils.format("List is full with %d elements.", maxElements));
    }
    buffer.putInt(numElements * Integer.BYTES, val);
    numElements++;
    maxMergeBufferUsedBytes = Math.max(maxMergeBufferUsedBytes, numElements * Integer.BYTES);
  }

  public void set(int index, int val)
  {
    buffer.putInt(index * Integer.BYTES, val);
  }

  public int get(int index)
  {
    return buffer.getInt(index * Integer.BYTES);
  }

  public void reset()
  {

View on GitHub (pinned to 9b90983fd2)