prestodb/presto · error · IllegalStateException
Invalid field position selection after nulls removed: " + se
Error message
Invalid field position selection after nulls removed: " + selectedFieldPositionCount
What it means
In getPositionsSizeInBytes, AbstractRowBlock subtracts one field position for every selected row that is null. If the count goes negative, the selected positions do not correspond to valid row positions in this block, so the library throws IllegalStateException to signal a corrupted/inconsistent selection set.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/AbstractRowBlock.java:233
if (selectedRowPositions == positionCount) {
return getSizeInBytes();
}
OptionalInt fixedSizePerFieldPosition = fixedSizeInBytesForAllFieldsPerPosition();
if (fixedSizePerFieldPosition.isPresent()) {
// All field blocks are fixed size per position, no specific position mapping is necessary
int selectedFieldPositionCount = selectedRowPositions;
boolean[] rowIsNull = getRowIsNull();
if (rowIsNull != null) {
// Some positions in usedPositions may be null which must be removed from the selectedFieldPositionCount
int offsetBase = getOffsetBase();
for (int i = 0; i < positions.length; i++) {
if (positions[i] && rowIsNull[i + offsetBase]) {
selectedFieldPositionCount--; // selected row is null, don't include it in the selected field positions
}
}
if (selectedFieldPositionCount < 0) {
throw new IllegalStateException("Invalid field position selection after nulls removed: " + selectedFieldPositionCount);
}
}
return ((Integer.BYTES + Byte.BYTES) * (long) selectedRowPositions) + (fixedSizePerFieldPosition.getAsInt() * (long) selectedFieldPositionCount);
}
return getSpecificPositionsSizeInBytes(positions, selectedRowPositions);
}
private long getSpecificPositionsSizeInBytes(boolean[] positions, int selectedRowPositions)
{
int positionCount = getPositionCount();
int offsetBase = getOffsetBase();
boolean[] rowIsNull = getRowIsNull();
// No fixed width size per row, specific positions used must be tracked
int totalFieldPositions = getRawFieldBlocks()[0].getPositionCount();
boolean[] fieldPositions;
int selectedFieldPositionCount;
if (rowIsNull == null) {View on GitHub (pinned to 55bb57d202)
Solutions
- Ensure the positions boolean array was computed for this exact block and matches its position count.
- Recompute the selection from the block's own positions rather than reusing masks across blocks.
- Check whether the caller applied selection logic before or after filtering nulls inconsistently; unify on the block's rowIsNull.
Defensive patterns
Strategy: validation
Validate before calling
checkArgument(positions.length == rowBlock.getPositionCount(),
"selection mask length %s does not match block position count %s",
positions.length, rowBlock.getPositionCount()); Try / catch
try {
long size = rowBlock.getPositionsSizeInBytes(positions, selectedPositions);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("Invalid field position selection")) {
// recompute selection for this block
} else {
throw e;
}
} Prevention
- Never reuse position selection masks across different blocks.
- Build selection masks from the block's own rowIsNull array.
- Add invariant checks after computing selections in custom operators.
When it happens
Trigger: Calling getPositionsSizeInBytes with a positions selection array whose length or indexing does not match the block's positions, or a selection computed against a different block.
Common situations: Custom operators or page-repartitioning code passing selection masks built for another block; bugs in compaction code that mixes position selections across blocks.
Related errors
- Number of fields in RowBlock must be positive
- position is not valid
- Map key is null at position: " + position
- position is not valid: " + position
- Current entry must be closed before a null can be written
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/bbc9d960c7d6f922.
Report an issue: GitHub.