prestodb/presto · error · java.lang.IndexOutOfBoundsException
Invalid channel %d in page with %s channels
Error message
Invalid channel %d in page with %s channels
What it means
Page.dropColumn removes the channel at channelIndex; the index must be within [0, channelCount). Out-of-range values would otherwise corrupt the block array copy, so the library throws IndexOutOfBoundsException.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/Page.java:435
}
public Page prependColumn(Block column)
{
if (column.getPositionCount() != positionCount) {
throw new IllegalArgumentException(String.format("Column does not have same position count (%s) as page (%s)", column.getPositionCount(), positionCount));
}
Block[] result = new Block[blocks.length + 1];
result[0] = column;
System.arraycopy(blocks, 0, result, 1, blocks.length);
return wrapBlocksWithoutCopy(positionCount, result);
}
public Page dropColumn(int channelIndex)
{
if (channelIndex < 0 || channelIndex >= getChannelCount()) {
throw new IndexOutOfBoundsException(format("Invalid channel %d in page with %s channels", channelIndex, getChannelCount()));
}
Block[] result = new Block[getChannelCount() - 1];
System.arraycopy(blocks, 0, result, 0, channelIndex);
System.arraycopy(blocks, channelIndex + 1, result, channelIndex, getChannelCount() - channelIndex - 1);
return wrapBlocksWithoutCopy(positionCount, result);
}
private long updateRetainedSize()
{
AtomicLong retainedSizeInBytes = new AtomicLong(INSTANCE_SIZE + sizeOf(blocks));
Set<Object> referenceSet = newSetFromMap(new IdentityHashMap<>());
for (Block block : blocks) {
block.retainedBytesForEachPart((object, size) -> {
if (referenceSet.add(object)) {
retainedSizeInBytes.addAndGet(size);
}
});View on GitHub (pinned to 55bb57d202)
Solutions
- Check 0 <= channelIndex < page.getChannelCount() before calling dropColumn
- Track which columns have already been dropped to avoid double-drop
- Derive channel indexes from the actual page schema (e.g. by locating the column by type/name) instead of hardcoding
Example fix
// before
page.dropColumn(rowIdChannel);
page.dropColumn(rowIdChannel); // second call throws
// after
if (rowIdChannel >= 0 && rowIdChannel < page.getChannelCount()) {
page = page.dropColumn(rowIdChannel);
rowIdChannel = -1;
} Defensive patterns
Strategy: type-guard
Validate before calling
if (channelIndex < 0 || channelIndex >= page.getChannelCount()) {
throw new IllegalArgumentException("cannot drop channel " + channelIndex
+ " from page with " + page.getChannelCount() + " channels");
}
page = page.dropColumn(channelIndex); Type guard
boolean canDrop(Page page, int channelIndex) {
return channelIndex >= 0 && channelIndex < page.getChannelCount();
} Try / catch
try {
page = page.dropColumn(channelIndex);
} catch (IndexOutOfBoundsException e) {
if (!e.getMessage().contains("Invalid channel")) throw e;
return page; // channel already absent
} Prevention
- Recompute channel indexes after each schema change (dropColumn shifts later columns)
- Guard against double-dropping the same channel
- Resolve channel indexes by type/name rather than hardcoding
When it happens
Trigger: Calling page.dropColumn(i) with i < 0 or i >= page.getChannelCount() — e.g. dropping the same column twice, or using a channel index from a stale/different page layout.
Common situations: fillInRowIDs-style pipelines that drop a channel twice; operators hardcoding channel indexes after the page schema changed; dynamic column removal loops without bounds checks.
Related errors
- Invalid position %s and length %s in page with %s positions
- 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
- position is not valid:
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/17b434d5f8bbfad1.
Report an issue: GitHub.