prestodb/presto · error · IllegalArgumentException

otherOffset %d, length %d are invalid for otherSlice with le

Error message

otherOffset %d, length %d are invalid for otherSlice with length %d

What it means

bytesEqual compares a 128-bit value region of this block against a byte range of another Slice. The otherOffset/length pair must lie entirely within otherSlice (both non-negative and otherOffset + length <= otherSlice.length()); otherwise the comparison would read past the slice, so IllegalArgumentException is thrown.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlock.java:213

     * Is the byte sequences at the {@code position + offset} position in the 128-bit values of {@code length} bytes equal
     * to the byte sequence at {@code otherOffset} in {@code otherSlice}.
     *
     * @param position The position of 128-bit integer.
     * @param offset The offset to the position in the unit of 128-bit integers.
     * For example, offset = 1 means the next position (one 128-bit integer or 16 bytes) to the specified position.
     * This means we always compare starting at 128-bit integer boundaries.
     * @param otherSlice The slice to compare to.
     * @param otherOffset The offset in bytes to the start of otherSlice.
     * @param length The length to compare in bytes. It has to be a multiple of 16.
     * @return True if the bytes are the same, false otherwise.
     */
    @Override
    public boolean bytesEqual(int position, int offset, Slice otherSlice, int otherOffset, int length)
    {
        int num128Integers = getNum128Integers(length);
        checkValidRegion(positionCount, position + offset, num128Integers);
        if (otherOffset < 0 || length < 0 || otherOffset + length > otherSlice.length()) {
            throw new IllegalArgumentException(format("otherOffset %d, length %d are invalid for otherSlice with length %d", otherOffset, length, otherSlice.length()));
        }

        int currentPosition = (position + offset + positionOffset) * 2;
        for (int i = 0; i < num128Integers; i++) {
            if (values[currentPosition] != otherSlice.getLong(otherOffset) || values[currentPosition + 1] != otherSlice.getLong(otherOffset + SIZE_OF_LONG)) {
                return false;
            }

            currentPosition += 2;
            otherOffset += SIZE_OF_LONG * 2;
        }

        return true;
    }

    @Override
    public boolean mayHaveNull()
    {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Slice otherSlice to exactly the value being compared before calling: otherSlice = slice.slice(valueStart, INT128_BYTES).
  2. Validate otherOffset >= 0 && length >= 0 && otherOffset + length <= otherSlice.length() at the call site.
  3. Ensure length is a multiple of 16 for INT128 comparisons (getNum128Integers expects this).

Example fix

// before
block.bytesEqual(pos, 0, bigSlice, rawOffset, 8); // wrong length/bounds
// after
Slice value = bigSlice.slice(valueStart, Int128ArrayBlock.INT128_BYTES);
block.bytesEqual(pos, 0, value, 0, Int128ArrayBlock.INT128_BYTES);
Defensive patterns

Strategy: validation

Validate before calling

checkArgument(otherOffset >= 0 && length >= 0 && otherOffset + length <= otherSlice.length(),
    "bytesEqual range [%d, %d) out of slice length %d", otherOffset, otherOffset + length, otherSlice.length());

Type guard

boolean sliceRangeInBounds(Slice slice, int offset, int length) {
    return offset >= 0 && length >= 0 && offset + length <= slice.length();
}

Try / catch

try {
    equal = block.bytesEqual(position, 0, otherSlice, otherOffset, length);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("are invalid for otherSlice")) {
        throw new IllegalStateException("comparison slice not aligned to INT128 value boundaries", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling Int128ArrayBlock.bytesEqual(position, offset, otherSlice, otherOffset, length) where otherOffset < 0, length < 0, or otherOffset + length > otherSlice.length() — e.g. passing a Slice not sliced to the value boundary, or a length other than 16 in 128-bit comparisons.

Common situations: Hash/equality operators passing raw slices without adjusting an offset for the value start; comparing DECIMAL values against varbinary slices whose lengths differ; forgetful slicing after copying a sub-range of a larger buffer.

Related errors


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