prestodb/presto · error · IllegalArgumentException

position is not valid

Error message

position is not valid

What it means

checkReadablePosition guards every position-based read on Int128ArrayBlockBuilder (getLong, isNull, writePositionTo, getSingleValueBlock, copyPositions). Any position outside [0, getPositionCount()) is rejected with IllegalArgumentException because the builder has no value at that index.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlockBuilder.java:439

        return new Int128ArrayBlock(0, length, newValueIsNull, newValues);
    }

    @Override
    public String getEncodingName()
    {
        return Int128ArrayBlockEncoding.NAME;
    }

    @Override
    public String toString()
    {
        return format("Int128ArrayBlockBuilder(%d){positionCount=%d}", hashCode(), getPositionCount());
    }

    private void checkReadablePosition(int position)
    {
        if (position < 0 || position >= getPositionCount()) {
            throw new IllegalArgumentException("position is not valid");
        }
    }

    @Override
    public long getLongUnchecked(int internalPosition, int offset)
    {
        assert internalPositionInRange(internalPosition, getOffsetBase(), getPositionCount());
        assert offset == 0 || offset == 8 : "offset must be 0 or 8";
        return values[internalPosition * 2 + bitCount(offset)];
    }

    @Override
    public boolean isNullUnchecked(int internalPosition)
    {
        assert mayHaveNull() : "no nulls present";
        assert internalPositionInRange(internalPosition, getOffsetBase(), getPositionCount());
        return valueIsNull[internalPosition];
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Clamp/validate the loop bound: iterate i < block.getPositionCount().
  2. Only read after entries are closed (closeEntry) so positionCount reflects written values.
  3. Re-fetch positions from the current block instance instead of caching indexes across rebuilds.

Example fix

// before
for (int i = 0; i <= block.getPositionCount(); i++) { block.isNull(i); }
// after
for (int i = 0; i < block.getPositionCount(); i++) { block.isNull(i); }
Defensive patterns

Strategy: validation

Validate before calling

if (position < 0 || position >= block.getPositionCount()) {
    throw new IllegalArgumentException("position out of range: " + position);
}

Type guard

boolean readablePosition(Block b, int position) {
    return position >= 0 && position < b.getPositionCount();
}

Try / catch

try {
    value = builder.getLong(position, offset);
} catch (IllegalArgumentException e) {
    log.warn("Bad position {} on builder with {} positions", position, builder.getPositionCount());
    return null;
}

Prevention

When it happens

Trigger: Reading at a position equal to or greater than positionCount — commonly position == positionCount when iterating with <=, reading after an unfinished entry, or using stale indexes after the builder grew/reset.

Common situations: Off-by-one loops over block positions; reading a builder before closeEntry/finalization changed positionCount; reusing cached position indexes after block rebuild or page operator restarts.

Related errors


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