prestodb/presto · error · IllegalArgumentException
Invalid positions array size %d, actual position count is %d
Error message
Invalid positions array size %d, actual position count is %d
What it means
BlockUtil.checkValidPositions requires a boolean[] selection mask to have exactly one entry per block position. It throws IllegalArgumentException when positions.length differs from the block's positionCount, because a mismatched mask would silently select or skip the wrong rows.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/BlockUtil.java:68
static void checkArrayRange(boolean[] array, int offset, int length)
{
requireNonNull(array, "array is null");
if (offset < 0 || length < 0 || offset + length > array.length) {
throw new IndexOutOfBoundsException(format("Invalid offset %s and length %s in array with %s elements", offset, length, array.length));
}
}
static void checkValidRegion(int positionCount, int positionOffset, int length)
{
if (positionOffset < 0 || length < 0 || positionOffset + length > positionCount) {
throw new IndexOutOfBoundsException(format("Invalid position %s and length %s in block with %s positions", positionOffset, length, positionCount));
}
}
static void checkValidPositions(boolean[] positions, int positionCount)
{
if (positions.length != positionCount) {
throw new IllegalArgumentException(format("Invalid positions array size %d, actual position count is %d", positions.length, positionCount));
}
}
static void checkValidPosition(int position, int positionCount)
{
if (position < 0 || position >= positionCount) {
throw new IllegalArgumentException(format("Invalid position %s in block with %s positions", position, positionCount));
}
}
static void checkValidSliceRange(int sourceIndex, int length)
{
//sourceIndex + length can overflow integer range
if (sourceIndex > MAX_ARRAY_SIZE - length) {
throw new SliceTooLargeException(format("Cannot allocate slice larger than %d bytes", MAX_ARRAY_SIZE));
}
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Rebuild the boolean[] mask for the current block's getPositionCount() instead of reusing a stale one
- Assert positions.length == positionCount at the mask-construction site
- Catch IllegalArgumentException to report a mask-vs-block cardinality mismatch with both sizes
Example fix
// before block.getPositions(cachedMask, positionCount, mask); // after boolean[] mask = new boolean[block.getPositionCount()]; block.getPositions(mask, block.getPositionCount(), mask);
Defensive patterns
Strategy: validation
Validate before calling
if (positions.length != block.getPositionCount()) {
positions = new boolean[block.getPositionCount()];
} Type guard
boolean isValidPositionsMask(boolean[] positions, int positionCount) {
return positions != null && positions.length == positionCount;
} Try / catch
try {
result = block.getPositions(positions, offset, size);
} catch (IllegalArgumentException e) {
throw new PrestoException(GENERIC_INTERNAL_ERROR, "positions mask size mismatch", e);
} Prevention
- Rebuild selection masks per page instead of caching across pages
- Size masks from block.getPositionCount() at use time
- Unit-test operators with pages of varying position counts
When it happens
Trigger: Calling Block.getPositions with a boolean[] built against a different (stale, shorter, or longer) positionCount than the target block — e.g. reusing a mask from a previous page.
Common situations: Filter operators caching selection masks across pages of differing sizes; vectorized engines reusing buffers after a block resize; custom operators building masks from upstream column of mismatched cardinality.
Related errors
- Invalid position %s in block with %s positions
- dictionarySourceIds must be the same
- blocks is empty
- Column does not have same position count (%s) as page (%s)
- QualifiedObjectName should have exactly 3 parts, found %s: %
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/4f950e1474168fc0.
Report an issue: GitHub.