prestodb/presto · error · IllegalArgumentException

length %d must be a multiple of 16.

Error message

length %d must be a multiple of 16.

What it means

BlockUtil.getNum128Integers converts a byte length into a count of 128-bit integers (length / 16). Because the conversion only works for whole 128-bit units, the length must be an exact multiple of 16 (SIZE_OF_LONG * 2); otherwise the operation would silently truncate partial data, so the library throws this IllegalArgumentException. It is a strict alignment requirement on the input length.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/BlockUtil.java:285

        newIsNull[desiredLength - 1] = true;
        return newIsNull;
    }

    static int[] appendNullToOffsetsArray(int[] offsets, int offsetBase, int positionCount)
    {
        checkArrayRange(offsets, offsetBase, positionCount + 1);

        int desiredLength = offsetBase + positionCount + 2;
        int[] newOffsets = Arrays.copyOf(offsets, desiredLength);
        newOffsets[desiredLength - 1] = newOffsets[desiredLength - 2];
        return newOffsets;
    }

    public static int getNum128Integers(int length)
    {
        int num128Integers = length / SIZE_OF_LONG / 2;
        if (num128Integers * SIZE_OF_LONG * 2 != length) {
            throw new IllegalArgumentException(format("length %d must be a multiple of 16.", length));
        }
        return num128Integers;
    }

    /**
     * Returns the input blocks array if all blocks are already loaded, otherwise returns a new blocks array with all blocks loaded
     */
    static Block[] ensureBlocksAreLoaded(Block[] blocks)
    {
        for (int i = 0; i < blocks.length; i++) {
            Block loaded = blocks[i].getLoadedBlock();
            if (loaded != blocks[i]) {
                // Transition to new block creation mode after the first newly loaded block is encountered
                Block[] loadedBlocks = blocks.clone();
                loadedBlocks[i++] = loaded;
                for (; i < blocks.length; i++) {
                    loadedBlocks[i] = blocks[i].getLoadedBlock();
                }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Ensure the input length is a multiple of 16 before calling: round/slice the buffer to whole 128-bit units.
  2. Verify the byte width of the values being processed is 16 (two longs); if the data is narrower, use the correct vectorized helper for that width.
  3. Check slicing logic upstream (offsets/lengths math) for misalignment; add an assertion length % 16 == 0 where buffers are constructed.

Example fix

// before
int n = BlockUtil.getNum128Integers(sliceLength); // throws when sliceLength % 16 != 0
// after
checkArgument(sliceLength % 16 == 0, "length must be a multiple of 16, got %s", sliceLength);
int n = BlockUtil.getNum128Integers(sliceLength);
Defensive patterns

Strategy: validation

Validate before calling

if (length < 0 || length % 16 != 0) {
    throw new IllegalArgumentException("length must be a non-negative multiple of 16: " + length);
}
int num128Integers = BlockUtil.getNum128Integers(length);

Type guard

boolean is16ByteAligned(int length) {
    return length >= 0 && (length & 15) == 0;
}

Try / catch

try {
    n = BlockUtil.getNum128Integers(length);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("must be a multiple of 16")) {
        throw new IllegalStateException("misaligned buffer passed to 128-bit path: " + length, e);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling getNum128Integers with a length that is not divisible by 16, e.g. getNum128Integers(20) or getNum128Integers(0-modulo-8-only sizes like 8 or 24). Usually reached from fixed-width block/vectorized hashing paths where a buffer was sliced to a non-aligned boundary.

Common situations: Custom slice/buffer arithmetic producing misaligned lengths (off-by-N slicing of a fixed-width value buffer); a custom block type whose element size is not 16 bytes being fed into a 128-bit vectorized routine; version changes where value widths changed but the hash path assumed 16-byte alignment.

Related errors


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