prestodb/presto · error · IllegalArgumentException
positionCount is negative
Error message
positionCount is negative
What it means
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.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/DictionaryBlock.java:101
}
public DictionaryBlock(int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted)
{
this(0, positionCount, dictionary, ids, dictionaryIsCompacted, randomDictionaryId());
}
public DictionaryBlock(int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted, DictionaryId dictionarySourceId)
{
this(0, positionCount, dictionary, ids, dictionaryIsCompacted, dictionarySourceId);
}
public DictionaryBlock(int idsOffset, int positionCount, Block dictionary, int[] ids, boolean dictionaryIsCompacted, DictionaryId dictionarySourceId)
{
requireNonNull(dictionary, "dictionary is null");
requireNonNull(ids, "ids is null");
if (positionCount < 0) {
throw new IllegalArgumentException("positionCount is negative");
}
this.idsOffset = idsOffset;
if (ids.length - idsOffset < positionCount) {
throw new IllegalArgumentException("ids length is less than positionCount");
}
this.positionCount = positionCount;
this.dictionary = dictionary;
this.ids = ids;
this.dictionarySourceId = requireNonNull(dictionarySourceId, "dictionarySourceId is null");
this.retainedSizeInBytes = INSTANCE_SIZE + dictionary.getRetainedSizeInBytes() + sizeOf(ids);
if (dictionaryIsCompacted) {
this.sizeInBytes = dictionary.getSizeInBytes() + (Integer.BYTES * (long) positionCount);
this.uniqueIds = dictionary.getPositionCount();
}
}View on GitHub (pinned to 55bb57d202)
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
Example fix
// before int positionCount = endOffset - startOffset; // can be negative on corrupt metadata new DictionaryBlock(0, positionCount, dictionary, ids, false, dictionarySourceId); // after int positionCount = endOffset - startOffset; checkArgument(positionCount >= 0, "Invalid positionCount %s computed from offsets", positionCount); new DictionaryBlock(0, positionCount, dictionary, ids, false, dictionarySourceId);
Defensive patterns
Strategy: validation
Validate before calling
static DictionaryBlock safeDictionaryBlock(int idsOffset, int positionCount, Block dictionary, int[] ids) {
checkArgument(positionCount >= 0, "positionCount must be >= 0, got %s", positionCount);
checkArgument(ids.length - idsOffset >= positionCount, "ids too short");
return new DictionaryBlock(idsOffset, positionCount, dictionary, ids, false, DictionaryId.randomDictionaryId());
} Try / catch
try {
return new DictionaryBlock(idsOffset, positionCount, dictionary, ids, false, sourceId);
} catch (IllegalArgumentException e) {
throw new dataCorruptionException("Bad dictionary block dimensions: " + e.getMessage(), e);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ids length is less than positionCount
- array1 and array2 cannot be null and should have same length
- arrayOffset is negative
- positionCount is negative
- New column does not have same number of rows as old column
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/8c57c04928c79a7d.
Report an issue: GitHub.