prestodb/presto · error · IllegalArgumentException

position is not valid

Error message

position is not valid

What it means

checkReadablePosition guards every public position-accessing method of Int128ArrayBlock (getLong, isNull, writePositionTo, getSingleValueBlock, copyPositions). Any position outside [0, getPositionCount()) is invalid because the block only exposes its visible position range; IllegalArgumentException is thrown rather than reading out of bounds.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlock.java:337

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

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

    @Override
    public String toString()
    {
        return format("Int128ArrayBlock(%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 int getOffsetBase()
    {
        return positionOffset;
    }

    @Override

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Clamp/bound loops with the block's own getPositionCount(): for (int i = 0; i < block.getPositionCount(); i++).
  2. Translate parent-block positions to region-relative positions before calling accessors on a region view.
  3. Check position bounds explicitly before access when the position comes from external input (e.g. join probes, output channel indices).

Example fix

// before
for (int i = 0; i <= region.getPositionCount(); i++) { region.isNull(i); } // off-by-one
// after
for (int i = 0; i < region.getPositionCount(); i++) { region.isNull(i); }
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

try {
    value = block.getLong(position, 0);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("position is not valid")) {
        throw new IllegalStateException("stale position " + position + " for block count " + block.getPositionCount(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling any accessor with position < 0 or position >= getPositionCount(); iterating with a stale position count after the block was replaced by a region/getRegion view with fewer positions; using an absolute source position on a sliced block instead of a relative one.

Common situations: Operators caching a position index across page boundaries; using the parent block's positions on a getRegion result; off-by-one loops written as i <= positionCount; reusing positions from a previous page whose count was larger.

Related errors


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