prestodb/presto · error · IllegalArgumentException

position is not valid

Error message

position is not valid

What it means

ByteArrayBlock.checkReadablePosition throws IllegalArgumentException when a caller asks for a position outside the valid range [0, getPositionCount()). Read APIs such as getByte, isNull, writePositionTo, getSingleValueBlock, copyPositions and toLong all funnel through this guard so the block never reads out of bounds.

Source

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

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

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

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

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

    @Override
    public int getOffsetBase()
    {
        return arrayOffset;
    }

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

    @Override

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Clamp/bound loops with block.getPositionCount() rather than an external row count
  2. Check 0 <= position && position < block.getPositionCount() before each read
  3. Verify the positions array passed to copyPositions contains only indexes within range
  4. Trace where the invalid position originates — usually an upstream page or operator produced fewer rows than expected

Example fix

// before
for (int i = 0; i < expectedRows; i++) value = block.getByte(i); // may throw
// after
for (int i = 0; i < block.getPositionCount(); i++) value = block.getByte(i);
Defensive patterns

Strategy: validation

Validate before calling

if (position < 0 || position >= block.getPositionCount()) {
    throw new IllegalArgumentException("position " + position + " out of range [0, " + block.getPositionCount() + ")");
}
byte value = block.getByte(position);

Type guard

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

Try / catch

try {
    byte v = block.getByte(position);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("position is not valid")) {
        throw new IllegalStateException("read past block end; positionCount=" + block.getPositionCount());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling block.getByte(position) or block.isNull(position) with position < 0 or position >= block.getPositionCount(); iterating with a stale/hardcoded position count; copyPositions with a positions array containing out-of-range indexes; using a position from a different (larger) block.

Common situations: Loops bounded by a wrong variable (e.g. logical row count vs physical block positionCount); aggregating blocks from pages with differing row counts after a filter; operator code caching a positionCount before a block was trimmed or reassigned.

Related errors


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