{"record":{"id":"d84f6214d1f6c317","repo":"apache/druid","slug":"size-d-must-be-non-negative","errorCode":null,"errorMessage":"Size[%d] must be non-negative","messagePattern":"Size\\[(.+?)\\] must be non-negative","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/data/RangeIndexedInts.java","lineNumber":39,"sourceCode":"\nimport org.apache.druid.java.util.common.IAE;\nimport org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;\n\n/**\n * Reusable IndexedInts that returns sequences [0, 1, ..., N].\n */\npublic class RangeIndexedInts implements IndexedInts\n{\n  private int size;\n\n  public RangeIndexedInts()\n  {\n  }\n\n  public void setSize(int size)\n  {\n    if (size < 0) {\n      throw new IAE(\"Size[%d] must be non-negative\", size);\n    }\n    this.size = size;\n  }\n\n  @Override\n  public int size()\n  {\n    return size;\n  }\n\n  @Override\n  public int get(int index)\n  {\n    if (index < 0 || index >= size) {\n      throw new IAE(\"index[%d] >= size[%d] or < 0\", index, size);\n    }\n    return index;\n  }","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/data/RangeIndexedInts.java#L21-L57","documentation":"Validation guard on the reusable RangeIndexedInts setter: setSize is meant to configure the reusable [0..N-1] sequence before use, and a negative size would make size()/get() nonsensical. It fires when a cursor factory or test helper (getRow, mockSelectors) configures the reusable instance with a negative row size, which would indicate a corrupted row-length source or a misconfigured selector; the row size handed to the cursor must be >= 0.","triggerScenarios":"Calling setSize(n) with a negative n, typically from a row-holder (getRow) that copied a negative row count from an upstream source or from mock selectors in tests.","commonSituations":"Cursor/row arithmetic producing a negative count when reading near the end of a segment; test mocks wired with bad sizes.","solutions":["Clamp or validate the computed row count to >= 0 before calling setSize","Fix the upstream computation that produced the negative size (e.g. max(0, end - start))","If this comes from getRow(), check the cursor's range/end offsets for overflow"],"exampleFix":"// before\nrangeIndexedInts.setSize(end - start);\n// after\nrangeIndexedInts.setSize(Math.max(0, end - start));","handlingStrategy":"validation","validationCode":"int size = end - start; if (size < 0) size = 0; rangeIndexedInts.setSize(size);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp computed sizes with Math.max(0, ...)","Audit cursor offset arithmetic for negative results","Validate mock sizes in tests"],"tags":["druid","segment","query"],"backgroundTag":"value-out-of-range","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}