prestodb/presto · error · IllegalArgumentException

offsets length is less than positionCount

Error message

offsets length is less than positionCount

What it means

The offsets array must contain positionCount + 1 entries starting at arrayOffset (offsets[i] and offsets[i+1] delimit each value). If offsets.length - arrayOffset < positionCount + 1 there are not enough boundary entries to decode every position, so the constructor throws IllegalArgumentException.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/VariableWidthBlock.java:85

    VariableWidthBlock(int arrayOffset, int positionCount, Slice slice, int[] offsets, boolean[] valueIsNull)
    {
        if (arrayOffset < 0) {
            throw new IllegalArgumentException("arrayOffset is negative");
        }
        this.arrayOffset = arrayOffset;
        if (positionCount < 0) {
            throw new IllegalArgumentException("positionCount is negative");
        }
        this.positionCount = positionCount;

        if (slice == null) {
            throw new IllegalArgumentException("slice is null");
        }
        this.slice = slice;

        if (offsets.length - arrayOffset < (positionCount + 1)) {
            throw new IllegalArgumentException("offsets length is less than positionCount");
        }
        this.offsets = offsets;

        if (valueIsNull != null && valueIsNull.length - arrayOffset < positionCount) {
            throw new IllegalArgumentException("valueIsNull length is less than positionCount");
        }
        this.valueIsNull = valueIsNull;

        sizeInBytes = offsets[arrayOffset + positionCount] - offsets[arrayOffset] + ((Integer.BYTES + Byte.BYTES) * (long) positionCount);
        retainedSizeInBytes = INSTANCE_SIZE + slice.getRetainedSize() + sizeOf(valueIsNull) + sizeOf(offsets);
    }

    @Override
    public final int getPositionOffset(int position)
    {
        return offsets[position + arrayOffset];
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Ensure offsets has at least arrayOffset + positionCount + 1 entries (include the trailing sentinel).
  2. Verify positionCount matches the offsets array actually passed, not a different block's.
  3. Check the serialization/read path for truncation producing short offsets arrays.

Example fix

// before
int[] offsets = new int[positions.length]; // missing trailing entry
new VariableWidthBlock(0, positions.length, slice, offsets, null);
// after
int[] offsets = new int[positions.length + 1]; // +1 sentinel
new VariableWidthBlock(0, positions.length, slice, offsets, null);
Defensive patterns

Strategy: validation

Validate before calling

checkState(offsets.length - arrayOffset >= positionCount + 1,
    "offsets too short: need %s, have %s", positionCount + 1 + arrayOffset, offsets.length);

Try / catch

try {
    new VariableWidthBlock(arrayOffset, positionCount, slice, offsets, valueIsNull);
} catch (IllegalArgumentException e) {
    // inspect page truncation / mismatched offsets source
}

Prevention

When it happens

Trigger: Constructing VariableWidthBlock with an offsets array shorter than arrayOffset + positionCount + 1; typical when positionCount was computed from data length but offsets came from a truncated or differently-sized page.

Common situations: Corrupt/truncated serialized pages; mixing offsets arrays between blocks with different position counts; off-by-one when building offsets manually (forgetting the final sentinel entry).

Related errors


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