apache/druid · error · IllegalArgumentException
Index[ ] >= size[ ]
Error message
Index[%d] >= size[%d]
What it means
Indexed.checkIndex validates that an index used to look up an element in an Indexed collection is within [0, size). The library throws this IAE whenever index >= size to fail fast rather than reading out of bounds from the underlying data structure. The odd format is a quirk: '%s' would be more accurate than the mismatched '%d' on the first argument, but the values are index and size.
Solutions
- Print the collection's size() next to the offending index and fix the loop bound to `index < size()`
- Ensure the size you bound iteration by comes from the same Indexed instance you call get() on
- Check for off-by-one errors (i <= size() instead of i < size())
- If indexes come from another column (e.g. IndexedInts offsets), validate them against this collection's size before lookup
Example fix
// before
for (int i = 0; i <= indexed.size(); i++) { process(indexed.get(i)); }
// after
for (int i = 0; i < indexed.size(); i++) { process(indexed.get(i)); } Defensive patterns
Strategy: validation
Validate before calling
if (index < 0 || index >= indexed.size()) { throw new IllegalArgumentException("index " + index + " out of range, size=" + indexed.size()); } Type guard
boolean inBounds(Indexed<?> col, int i) { return col != null && i >= 0 && i < col.size(); } Try / catch
try { value = indexed.get(i); } catch (IllegalArgumentException e) { log.error("index %d out of bounds (size=%d)", i, indexed.size()); throw e; } Prevention
- Always iterate with i < indexed.size()
- Derive loop bounds from the same object you call get() on
- Avoid caching sizes across segment reloads
When it happens
Trigger: Calling Indexed.get(index) (or via IndexedInts/IndexedLongs accessor paths) with an index equal to or greater than the collection's size(), or a stale index held after the column shrank or was re-read.
Common situations: Row-by-row iteration using a cached row count from a different segment version; off-by-one loops (i <= size()); reading a column after the segment was replaced or partially loaded.
Related errors
- != 0
- Index[ ] >= size[ ] or < 0
- index[ ] >= size[ ] or < 0
- Actual Row count mismatch. Expected
- Attempt to add row to swapped-out sink for segment
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/c0c4742e2a421723.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/data/Indexed.java:127
return false;
}
/**
* Checks if {@code index} is between 0 and {@code size}. Similar to Preconditions.checkElementIndex() except this
* method throws {@link IAE} with custom error message.
* <p>
* Used here to get existing behavior(same error message and exception) of V1 {@link GenericIndexed}.
*
* @param index identifying an element of an {@link Indexed}
* @param size size of the {@link Indexed}
*/
static void checkIndex(int index, int size)
{
if (index < 0) {
throw new IAE("Index[%s] < 0", index);
}
if (index >= size) {
throw new IAE("Index[%d] >= size[%d]", index, size);
}
}
}
View on GitHub (pinned to 9b90983fd2)