prestodb/presto · error · IllegalArgumentException
offset must be 0 or 8
Error message
offset must be 0 or 8
What it means
An Int128 value is 16 bytes stored as two longs. getLong(position, offset) only accepts offsets of 0 (low 64 bits) or 8 (high 64 bits); any other offset would read unaligned or out-of-value data, so IllegalArgumentException is thrown.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlock.java:143
consumer.accept(values, sizeOf(values));
if (valueIsNull != null) {
consumer.accept(valueIsNull, sizeOf(valueIsNull));
}
consumer.accept(this, INSTANCE_SIZE);
}
@Override
public int getPositionCount()
{
return positionCount;
}
@Override
public long getLong(int position, int offset)
{
checkReadablePosition(position);
if (offset != 0 && offset != 8) {
throw new IllegalArgumentException("offset must be 0 or 8");
}
return getLongUnchecked(position + positionOffset, offset);
}
/**
* Get the Slice starting at {@code this.positionOffset + offset} in the value at {@code position} with {@code length} bytes.
*
* @param position The logical position of the 128-bit integer in the values array.
* For example, position = 0 refers to the 128-bit integer at values[2] and values[3] if this.positionOffset = 1.
* @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 bytes starting at 128-bit integer boundaries.
* @param length The length in bytes. It has to be a multiple of 16.
*/
@Override
public Slice getSlice(int position, int offset, int length)
{
checkValidRegion(positionCount, offset, length / SIZE_OF_LONG / 2);View on GitHub (pinned to 55bb57d202)
Solutions
- Restrict the calling code to offsets 0 and 8 when the column type is 128-bit.
- Type-dispatch before reading: check the block type and use getRawSlice/getLongUnchecked-style access or Int128-specific helpers for generic iteration.
- Guard the call site: if (offset != 0 && offset != 8) handle via a 16-byte-aware path.
Example fix
// before long value = block.getLong(position, offset); // offset arbitrary // after checkArgument(offset == 0 || offset == 8, "INT128 supports offsets 0/8 only, got %s", offset); long value = block.getLong(position, offset);
Defensive patterns
Strategy: type-guard
Validate before calling
if (type instanceof DecimalType && ((DecimalType) type).isShortNotUsed()) {
checkArgument(offset == 0 || offset == 8, "INT128 getLong supports offsets 0/8 only, got %s", offset);
} Type guard
boolean isInt128SafeOffset(int offset) { return offset == 0 || offset == 8; } Try / catch
try {
value = block.getLong(position, offset);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("offset must be 0 or 8")) {
throw new IllegalStateException("generic 8-byte read applied to 128-bit column at offset " + offset, e);
}
throw e;
} Prevention
- Dispatch reads by block type instead of assuming fixed 8-byte widths.
- In generic loops over fixed-width blocks, cap offsets at the type's width.
- Add type-aware unit tests for operators run over DECIMAL(38,x) columns.
When it happens
Trigger: Calling Int128ArrayBlock.getLong(position, offset) with an offset other than 0 or 8 — e.g. generic code that assumes 8-byte fixed-width types and passes arbitrary byte offsets like 4, or loops offsetting by SIZE_OF_LONG beyond the two allowed values.
Common situations: Generic vectorized operators (hash, projection, aggregation) written for BIGINT being reused on DECIMAL(38,x)/INT128 columns; copy loops that walk past the 16-byte value boundary.
Related errors
- otherOffset %d, length %d are invalid for otherSlice with le
- offset must be 0 or 8
- Offset is not monotonically ascending. offsets[%s]=%s, offse
- A null map must have zero entries
- Number of fields in RowBlock must be positive
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/5629e1f1af21dd2a.
Report an issue: GitHub.