prestodb/presto · error · IllegalArgumentException

positionCount is negative

Error message

positionCount is negative

What it means

ShortArrayBlock's constructor validates its arguments before storing them. positionCount represents the number of entries in the block, and a negative count is meaningless, so the constructor throws IllegalArgumentException immediately rather than creating a corrupt block. This is a fail-fast guard against bad block construction.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/ShortArrayBlock.java:61

    @Nullable
    private final boolean[] valueIsNull;
    private final short[] values;

    private final long retainedSizeInBytes;

    public ShortArrayBlock(int positionCount, Optional<boolean[]> valueIsNull, short[] values)
    {
        this(0, positionCount, valueIsNull.orElse(null), values);
    }

    ShortArrayBlock(int arrayOffset, int positionCount, boolean[] valueIsNull, short[] values)
    {
        if (arrayOffset < 0) {
            throw new IllegalArgumentException("arrayOffset is negative");
        }
        this.arrayOffset = arrayOffset;
        if (positionCount < 0) {
            throw new IllegalArgumentException("positionCount is negative");
        }
        this.positionCount = positionCount;

        if (values.length - arrayOffset < positionCount) {
            throw new IllegalArgumentException("values length is less than positionCount");
        }
        this.values = values;

        if (valueIsNull != null && valueIsNull.length - arrayOffset < positionCount) {
            throw new IllegalArgumentException("isNull length is less than positionCount");
        }
        this.valueIsNull = valueIsNull;

        retainedSizeInBytes = INSTANCE_SIZE + sizeOf(valueIsNull) + sizeOf(values);
    }

    @Override
    public long getSizeInBytes()

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Check the caller's positionCount computation for swapped or underflowing arithmetic (e.g. end - start with end < start).
  2. Clamp or validate the value before constructing: if (positionCount < 0) throw ... or use Math.max(0, positionCount).
  3. Verify the data source (e.g. deserialized length field) is not corrupted; re-serialize the input.

Example fix

// before
int count = end - start;
Block block = new ShortArrayBlock(0, count, new short[8], null);
// after
int count = Math.max(0, end - start);
checkArgument(end >= start, "end before start");
Block block = new ShortArrayBlock(0, count, new short[8], null);
Defensive patterns

Strategy: validation

Validate before calling

if (positionCount < 0) {
    throw new IllegalArgumentException("positionCount must be >= 0, got " + positionCount);
}

Type guard

boolean isValidBlockShape(int arrayOffset, int positionCount, short[] values) {
    return arrayOffset >= 0 && positionCount >= 0 && values.length - arrayOffset >= positionCount;
}

Try / catch

try {
    Block block = new ShortArrayBlock(arrayOffset, positionCount, values, valueIsNull);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("positionCount is negative")) {
        positionCount = Math.max(0, positionCount); // or log and rethrow with context
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling ShortArrayBlock's constructor (directly or via factory methods like ShortArrayBlock.fromShortArray) with a negative positionCount argument.

Common situations: Custom block building code that computes positionCount via subtraction (e.g. end - start on swapped indices), off-by-one bugs in aggregation/partitioning code, or deserialization feeding a corrupted/underflowed int.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/31eacb007c4c64f7. Report an issue: GitHub.