prestodb/presto · error · java.lang.IndexOutOfBoundsException
Invalid position %s and length %s in page with %s positions
Error message
Invalid position %s and length %s in page with %s positions
What it means
Page.getRegion(positionOffset, length) extracts a sub-page; it throws IndexOutOfBoundsException when positionOffset is negative, length is negative, or positionOffset + length exceeds the page's positionCount. This guards against reading outside the page's valid position range.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/Page.java:185
/**
* Gets the values at the specified position as a single element page. The method creates independent
* copy of the data.
*/
public Page getSingleValuePage(int position)
{
Block[] singleValueBlocks = new Block[this.blocks.length];
for (int i = 0; i < this.blocks.length; i++) {
singleValueBlocks[i] = this.blocks[i].getSingleValueBlock(position);
}
return wrapBlocksWithoutCopy(1, singleValueBlocks);
}
// getRegion() is used to get a sub-page or region of a page based on the given positionOffset and length
public Page getRegion(int positionOffset, int length)
{
if (positionOffset < 0 || length < 0 || positionOffset + length > positionCount) {
throw new IndexOutOfBoundsException(format("Invalid position %s and length %s in page with %s positions", positionOffset, length, positionCount));
}
// Avoid creating new objects when region is same as original page
if (positionOffset == 0 && length == positionCount) {
return this;
}
// Create a new page view with the specified region
int channelCount = getChannelCount();
Block[] slicedBlocks = new Block[channelCount];
for (int i = 0; i < channelCount; i++) {
slicedBlocks[i] = blocks[i].getRegion(positionOffset, length);
}
return wrapBlocksWithoutCopy(length, slicedBlocks);
}
public Page appendColumn(Block block)
{View on GitHub (pinned to 55bb57d202)
Solutions
- Clamp length: use Math.min(offset + length, page.getPositionCount()) - offset before calling getRegion.
- Check the page's actual positionCount via getPositionCount() and compute the region bounds from it.
- Fix off-by-one arithmetic in the calling operator or pagination logic.
- Add an assertion/unit test that validates offsets against the page size for your custom operator.
Example fix
// before Page region = page.getRegion(pageOffset, batchSize); // after int len = Math.min(batchSize, page.getPositionCount() - pageOffset); Page region = len > 0 ? page.getRegion(pageOffset, len) : null;
Defensive patterns
Strategy: validation
Validate before calling
boolean isValidRegion(Page page, int offset, int length) {
return page != null && offset >= 0 && length >= 0 && offset + length <= page.getPositionCount();
} Type guard
Page safeGetRegion(Page page, int offset, int length) {
if (page == null || offset < 0 || length < 0 || offset + length > page.getPositionCount()) {
return null;
}
return page.getRegion(offset, length);
} Try / catch
try {
return page.getRegion(offset, length);
} catch (IndexOutOfBoundsException e) {
log.warn("Region request [%d,%d] outside page size %d", offset, length, page.getPositionCount());
return page.getPositionCount() > 0 ? page.getRegion(0, page.getPositionCount()) : Page.EMPTY;
} Prevention
- Always derive region bounds from page.getPositionCount(), never from assumed batch sizes.
- Clamp length with Math.min for the final page in pagination loops.
- Unit-test page slicing against boundary cases (0 rows, exactly 1 row, full page).
- Compute offsets in long or double-check arithmetic to avoid overflow producing negative lengths.
When it happens
Trigger: Calling page.getRegion(offset, len) with offset < 0, len < 0, or offset+len > page.getPositionCount(), e.g. requesting 1000 rows from a page that only has 500.
Common situations: Off-by-one errors in custom page processors/operators, pagination code assuming fixed page sizes larger than the actual final page, downstream operators not checking positionCount before slicing, or stale row counts after filtering.
Related errors
- Block does not have same position count
- Invalid channel %d in page with %s channels
- Column does not have same position count (%s) as page (%s)
- New column does not have same number of rows as old column
- Invalid position %s and length %s in block with %s positions
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/f252535d812c907a.
Report an issue: GitHub.