{"record":{"id":"73b904818262b01f","repo":"prestodb/presto","slug":"positioncount-is-negative-73b904","errorCode":null,"errorMessage":"positionCount is negative","messagePattern":"positionCount is negative","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/IntArrayBlock.java","lineNumber":63,"sourceCode":"    @Nullable\n    private final boolean[] valueIsNull;\n    private final int[] values;\n\n    private final long retainedSizeInBytes;\n\n    public IntArrayBlock(int positionCount, Optional<boolean[]> valueIsNull, int[] values)\n    {\n        this(0, positionCount, valueIsNull.orElse(null), values);\n    }\n\n    IntArrayBlock(int arrayOffset, int positionCount, boolean[] valueIsNull, int[] values)\n    {\n        if (arrayOffset < 0) {\n            throw new IllegalArgumentException(\"arrayOffset is negative\");\n        }\n        this.arrayOffset = arrayOffset;\n        if (positionCount < 0) {\n            throw new IllegalArgumentException(\"positionCount is negative\");\n        }\n        this.positionCount = positionCount;\n\n        if (values.length - arrayOffset < positionCount) {\n            throw new IllegalArgumentException(\"values length is less than positionCount\");\n        }\n        this.values = values;\n\n        if (valueIsNull != null && valueIsNull.length - arrayOffset < positionCount) {\n            throw new IllegalArgumentException(\"isNull length is less than positionCount\");\n        }\n        this.valueIsNull = valueIsNull;\n\n        retainedSizeInBytes = INSTANCE_SIZE + sizeOf(valueIsNull) + sizeOf(values);\n    }\n\n    @Override\n    public long getSizeInBytes()","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/IntArrayBlock.java#L45-L81","documentation":"IntArrayBlock requires a non-negative positionCount. Negative counts are impossible block sizes and indicate a caller bug (e.g. subtracting lengths or passing a sentinel), so the constructor throws IllegalArgumentException before any data is stored.","triggerScenarios":"Calling new IntArrayBlock(arrayOffset, positionCount, ...) with positionCount < 0, usually from length arithmetic like end - start where end < start.","commonSituations":"Slicing pages where start/end indexes got swapped; aggregate code subtracting consumed positions from a smaller total; deserializers reading a corrupted negative count field.","solutions":["Validate end >= start (or count >= 0) before constructing the block.","Fix the arithmetic that derives positionCount (e.g. Math.abs is wrong — correct the subtraction order).","Sanitize counts read from external/serialized sources before constructing blocks."],"exampleFix":"// before\nint count = endIdx - startIdx; // endIdx < startIdx -> negative\n// after\nint count = Math.max(0, endIdx - startIdx);","handlingStrategy":"validation","validationCode":"if (positionCount < 0) {\n    throw new IllegalArgumentException(\"positionCount must be non-negative\");\n}\nIntArrayBlock block = new IntArrayBlock(arrayOffset, positionCount, valueIsNull, values);","typeGuard":"boolean nonNegativeCount(int positionCount) { return positionCount >= 0; }","tryCatchPattern":"try {\n    block = new IntArrayBlock(offset, count, nulls, values);\n} catch (IllegalArgumentException e) {\n    block = IntArrayBlock.EMPTY_BLOCK; // or recompute count\n}","preventionTips":["Verify end >= start in slice arithmetic before computing counts","Sanitize counts read from serialized or external data","Use Math.max(0, end - start) defensively where ordering isn't guaranteed"],"tags":["presto","block","illegal-argument","constructor"],"backgroundTag":"invalid-position-count","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}