apache/druid · error · IllegalArgumentException
Size must be nonnegative
Error message
Size must be nonnegative
What it means
FrameProcessors.rangeSet(size) builds the IntSortedSet {0..size-1} representing channel indexes. A negative size is meaningless, so it throws IAE immediately. This helper is typically used to iterate over all channels of a stage or outputs of a processor.
Solutions
- Clamp the computed size to zero before calling: rangeSet(Math.max(0, n)).
- Fix the arithmetic that produced the negative count (often an off-by-one on an empty collection).
- Validate upstream that the channel/collection count is nonnegative before generating indexes.
Example fix
// before IntSortedSet set = FrameProcessors.rangeSet(channels.size() - removed); // after IntSortedSet set = FrameProcessors.rangeSet(Math.max(0, channels.size() - removed));
Defensive patterns
Strategy: validation
Validate before calling
if (size < 0) {
throw new IllegalArgumentException("rangeSet size must be >= 0, got " + size);
} Type guard
boolean validSize(int n) { return n >= 0; } Try / catch
try {
IntSortedSet s = FrameProcessors.rangeSet(n);
} catch (IllegalArgumentException e) {
// clamp or fix the computed count
} Prevention
- Clamp computed sizes with Math.max(0, n).
- Watch for size - removal arithmetic on possibly-empty collections.
- Unit-test counts for empty inputs.
When it happens
Trigger: Calling `FrameProcessors.rangeSet(-1)` directly, or indirectly via code that computes the count as `channels.size() - skipped` or `n - 1` where n is 0, producing a negative number.
Common situations: Off-by-one arithmetic on empty channel lists; subtracting a removal count that exceeds list size; miscomputed stage input counts during distributed query planning.
Related errors
- Cannot have a value when await != null or futures != null
- Cannot have null or empty column name
- Invalid partition number
- Invalid stageNumber [ ]
- Key is not sortable
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5e9ccd6cb1a27c82.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/frame/processor/FrameProcessors.java:134
.setVirtualColumns(virtualColumns)
.build();
// Despite appearances of columnar FrameCursorHolderFactory with its closers, it is currently safe to never close
// the CursorHolder that the FrameCursor comes from because it really does nothing. The row based
// FrameCursorHolderFactory has no closer stuff at all and is totally safe. If this ever changes, this method will
// probably need to wrap the cursor in something closeable, or be reworked to just return the CursorHolder so that
// callers can deal with closing the stuff.
return (FrameCursor) frameReader.makeCursorFactory(frame).makeCursorHolder(cursorBuildSpec).asCursor();
}
/**
* Creates a mutable sorted set from 0 to "size" (exclusive).
*
* @throws IllegalArgumentException if size is negative
*/
public static IntSortedSet rangeSet(final int size)
{
if (size < 0) {
throw new IAE("Size must be nonnegative");
}
final IntSortedSet set = new IntAVLTreeSet();
for (int i = 0; i < size; i++) {
set.add(i);
}
return set;
}
/**
* Selects a random element from a set of ints.
*/
public static int selectRandom(final IntSet ints)
{
final int idx = ThreadLocalRandom.current().nextInt(ints.size());
final IntIterator iterator = ints.iterator();View on GitHub (pinned to 9b90983fd2)