{"record":{"id":"8c57c04928c79a7d","repo":"prestodb/presto","slug":"positioncount-is-negative-8c57c0","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/DictionaryBlock.java","lineNumber":101,"sourceCode":"    }\n\n    public DictionaryBlock(int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted)\n    {\n        this(0, positionCount, dictionary, ids, dictionaryIsCompacted, randomDictionaryId());\n    }\n\n    public DictionaryBlock(int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted, DictionaryId dictionarySourceId)\n    {\n        this(0, positionCount, dictionary, ids, dictionaryIsCompacted, dictionarySourceId);\n    }\n\n    public DictionaryBlock(int idsOffset, int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted, DictionaryId dictionarySourceId)\n    {\n        requireNonNull(dictionary, \"dictionary is null\");\n        requireNonNull(ids, \"ids is null\");\n\n        if (positionCount < 0) {\n            throw new IllegalArgumentException(\"positionCount is negative\");\n        }\n\n        this.idsOffset = idsOffset;\n        if (ids.length - idsOffset < positionCount) {\n            throw new IllegalArgumentException(\"ids length is less than positionCount\");\n        }\n\n        this.positionCount = positionCount;\n        this.dictionary = dictionary;\n        this.ids = ids;\n        this.dictionarySourceId = requireNonNull(dictionarySourceId, \"dictionarySourceId is null\");\n        this.retainedSizeInBytes = INSTANCE_SIZE + dictionary.getRetainedSizeInBytes() + sizeOf(ids);\n\n        if (dictionaryIsCompacted) {\n            this.sizeInBytes = dictionary.getSizeInBytes() + (Integer.BYTES * (long) positionCount);\n            this.uniqueIds = dictionary.getPositionCount();\n        }\n    }","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/DictionaryBlock.java#L83-L119","documentation":"The DictionaryBlock constructor validates that positionCount is non-negative before using it. A negative positionCount would make the block report an impossible number of positions and break all downstream block math (offsets, slices, copyRegion), so IllegalArgumentException(\"positionCount is negative\") is thrown eagerly.","triggerScenarios":"Constructing DictionaryBlock directly or via factory methods with an int positionCount < 0 — typically from a bad length computed earlier (e.g. endOffset - startOffset underflow), a deserialized header with a corrupt count, or an arithmetic bug.","commonSituations":"Custom readers computing position counts from file metadata (Parquet/ORC num_values underflow); page serialization corruption; subtraction of offsets in the wrong order producing negative lengths.","solutions":["Clamp or validate positionCount before constructing: checkState(positionCount >= 0)","Fix the offset computation that produced the negative value (check subtraction order and source metadata)","Verify serialized page data is not corrupted (checksum/version mismatch)","Ensure deserialization code reads the count field with the correct endianness/width"],"exampleFix":"// before\nint positionCount = endOffset - startOffset; // can be negative on corrupt metadata\nnew DictionaryBlock(0, positionCount, dictionary, ids, false, dictionarySourceId);\n// after\nint positionCount = endOffset - startOffset;\ncheckArgument(positionCount >= 0, \"Invalid positionCount %s computed from offsets\", positionCount);\nnew DictionaryBlock(0, positionCount, dictionary, ids, false, dictionarySourceId);","handlingStrategy":"validation","validationCode":"static DictionaryBlock safeDictionaryBlock(int idsOffset, int positionCount, Block dictionary, int[] ids) {\n    checkArgument(positionCount >= 0, \"positionCount must be >= 0, got %s\", positionCount);\n    checkArgument(ids.length - idsOffset >= positionCount, \"ids too short\");\n    return new DictionaryBlock(idsOffset, positionCount, dictionary, ids, false, DictionaryId.randomDictionaryId());\n}","typeGuard":null,"tryCatchPattern":"try {\n    return new DictionaryBlock(idsOffset, positionCount, dictionary, ids, false, sourceId);\n} catch (IllegalArgumentException e) {\n    throw new dataCorruptionException(\"Bad dictionary block dimensions: \" + e.getMessage(), e);\n}","preventionTips":["Validate lengths derived from file metadata before building blocks","Check subtraction order when computing counts from offsets","Checksum/validate serialized pages before deserializing counts","Use checkArgument at boundaries so failures carry context"],"tags":["block","dictionary","argument-validation","presto"],"backgroundTag":"negative-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"}