prestodb/presto · error · IllegalArgumentException
position is not valid:
Error message
position is not valid:
What it means
RunLengthEncodedBlock.checkReadablePosition validates that a requested position lies within [0, positionCount). All primitive accessors (getLong, getInt, getSlice, etc.) route through it. Because all positions read the same underlying value, only the outer bounds matter — but an out-of-range index means the caller is addressing positions that do not exist in this block.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/RunLengthEncodedBlock.java:343
{
return format("RunLengthEncodedBlock(%d){positionCount=%d,value=%s}", hashCode(), getPositionCount(), value);
}
@Override
public Block getLoadedBlock()
{
Block loadedValueBlock = value.getLoadedBlock();
if (loadedValueBlock == value) {
return this;
}
return new RunLengthEncodedBlock(loadedValueBlock, positionCount);
}
private void checkReadablePosition(int position)
{
if (position < 0 || position >= positionCount) {
throw new IllegalArgumentException("position is not valid: " + position);
}
}
@Override
public byte getByteUnchecked(int internalPosition)
{
assert internalPositionInRange(internalPosition, getOffsetBase(), getPositionCount());
return value.getByte(0);
}
@Override
public short getShortUnchecked(int internalPosition)
{
assert internalPositionInRange(internalPosition, getOffsetBase(), getPositionCount());
return value.getShort(0);
}
@OverrideView on GitHub (pinned to 55bb57d202)
Solutions
- Bounds-check position against the current block's getPositionCount() before access
- Re-fetch the block/position count after any transform instead of caching stale counts
- Fix loop conditions to position < positionCount (not <=)
- Ensure the position passed belongs to the same block instance being read
Example fix
// before
for (int i = 0; i <= block.getPositionCount(); i++) { // off-by-one
long v = block.getLong(i, 0);
}
// after
for (int i = 0; i < block.getPositionCount(); i++) {
long v = block.getLong(i, 0);
} Defensive patterns
Strategy: validation
Validate before calling
// before reading any position from an RLE block
if (position < 0 || position >= block.getPositionCount()) {
throw new IllegalArgumentException("position " + position + " out of range for block with " + block.getPositionCount() + " positions");
}
long v = block.getLong(position, 0);
Try / catch
try {
return block.getLong(position, 0);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("position is not valid")) {
throw new IllegalStateException("stale position " + position + " vs current count " + block.getPositionCount() + "; refresh block reference", e);
}
throw e;
} Prevention
- Never cache positionCount across block transformations
- Use strict < comparisons in position loops
- Verify positions come from the same block instance (especially after page slicing)
When it happens
Trigger: Reading block position >= getPositionCount() or < 0, e.g. iterating with a stale position count after a block was compacted/filtered, or indexing with a source position from a different block.
Common situations: Operators holding an old positionCount snapshot after page slicing; off-by-one loops (position <= count); copying positions across blocks with different sizes during page reshuffling.
Related errors
- Expected value to contain a single position but has %s posit
- Invalid channel %d in page with %s channels
- Invalid position %s and length %s in block with %s positions
- positionCount is negative
- arrayOffset is negative
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/14cbe79db48ed9a2.
Report an issue: GitHub.