prestodb/presto · error · IllegalArgumentException

positionCount is negative

Error message

positionCount is negative

What it means

The ByteArrayBlock constructor rejects a negative positionCount (the number of logical positions in the block). A negative count is meaningless for a block and would corrupt downstream iteration and length checks, so the constructor throws this IllegalArgumentException as a precondition guard.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/ByteArrayBlock.java:70

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

    private final long retainedSizeInBytes;

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

    ByteArrayBlock(int arrayOffset, int positionCount, boolean[] valueIsNull, byte[] 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. Fix the count computation so it is non-negative; check for swapped range bounds (ensure end >= start before computing end - start).
  2. Replace -1 sentinel values with 0 or Optional before constructing the block.
  3. For an empty block, pass positionCount 0 rather than a negative or sentinel value.

Example fix

// before
int count = endIndex - startIndex; // startIndex > endIndex -> negative
new ByteArrayBlock(0, count, valueIsNull, values);
// after
int count = Math.max(0, endIndex - startIndex);
checkState(endIndex >= startIndex, "invalid range: start=%s end=%s", startIndex, endIndex);
new ByteArrayBlock(0, count, valueIsNull, values);
Defensive patterns

Strategy: validation

Validate before calling

if (positionCount < 0) {
    throw new IllegalArgumentException("computed positionCount is negative: " + positionCount);
}
new ByteArrayBlock(arrayOffset, positionCount, valueIsNull, values);

Type guard

boolean isValidPositionCount(int positionCount) {
    return positionCount >= 0;
}

Try / catch

try {
    block = new ByteArrayBlock(arrayOffset, positionCount, valueIsNull, values);
} catch (IllegalArgumentException e) {
    if (e.getMessage().equals("positionCount is negative")) {
        throw new IllegalStateException("negative position count from range [" + start + ", " + end + ")", e);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Constructing ByteArrayBlock with positionCount < 0, typically from a computed count such as end - start where start > end, or from subtraction underflow when deriving position counts from offsets.

Common situations: Slicing code where the range bounds were swapped (from > to); overflow in int arithmetic producing a negative count; connector code passing a result-size variable that was initialized to -1 as a sentinel and never replaced.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


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