{"record":{"id":"a8343969e6ca2193","repo":"apache/druid","slug":"list-is-full-with-d-elements","errorCode":null,"errorMessage":"List is full with %d elements.","messagePattern":"List is full with (.+?) elements\\.","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferIntList.java","lineNumber":57,"sourceCode":"  {\n    this.buffer = buffer;\n    this.maxElements = maxElements;\n    this.numElements = 0;\n    this.maxMergeBufferUsedBytes = 0;\n\n    if (buffer.capacity() < (maxElements * Integer.BYTES)) {\n      throw new IAE(\n          \"buffer for list is too small, was [%s] bytes, but need [%s] bytes.\",\n          buffer.capacity(),\n          maxElements * Integer.BYTES\n      );\n    }\n  }\n\n  public void add(int val)\n  {\n    if (numElements == maxElements) {\n      throw new IndexOutOfBoundsException(StringUtils.format(\"List is full with %d elements.\", maxElements));\n    }\n    buffer.putInt(numElements * Integer.BYTES, val);\n    numElements++;\n    maxMergeBufferUsedBytes = Math.max(maxMergeBufferUsedBytes, numElements * Integer.BYTES);\n  }\n\n  public void set(int index, int val)\n  {\n    buffer.putInt(index * Integer.BYTES, val);\n  }\n\n  public int get(int index)\n  {\n    return buffer.getInt(index * Integer.BYTES);\n  }\n\n  public void reset()\n  {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferIntList.java#L39-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"Underestimating cardinality of values merged into merge buffer; concurrent adds without synchronization; reused list instance across merges without resetting maxElements.","solutions":["Pre-size maxElements based on actual/estimated cardinality with headroom","Check numElements == maxElements before add(), or use a growable structure","Create a new larger ByteBufferIntList and copy when nearing capacity","Verify no double-adding due to concurrent/merged iteration"],"exampleFix":"// before\nlist.add(val); // may throw when full\n// after\nif (list.numElements() >= list.maxElements()) {\n  list = growList(list, list.maxElements() * 2);\n}\nlist.add(val);","handlingStrategy":"validation","validationCode":"if (list.size() >= list.maxElements()) { list = grow(list); }","typeGuard":"boolean canAdd(ByteBufferIntList l) { return l.numElements() < l.maxElements(); }","tryCatchPattern":"try { list.add(val); } catch (IndexOutOfBoundsException e) { if (e.getMessage().contains(\"List is full\")) { list = growAndRetry(val); } }","preventionTips":["Pre-size lists from cardinality estimates with headroom","Check size before every add in merge loops","Avoid reusing fixed-capacity lists across merges without reset"],"tags":["druid","groupby","index-out-of-bounds","fixed-capacity"],"backgroundTag":"index-out-of-bounds","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}