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

  1. Rebuild the boolean[] mask for the current block's getPositionCount() instead of reusing a stale one
  2. Assert positions.length == positionCount at the mask-construction site
  3. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/4f950e1474168fc0. Report an issue: GitHub.