{"record":{"id":"5629e1f1af21dd2a","repo":"prestodb/presto","slug":"offset-must-be-0-or-8","errorCode":null,"errorMessage":"offset must be 0 or 8","messagePattern":"offset must be 0 or 8","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlock.java","lineNumber":143,"sourceCode":"        consumer.accept(values, sizeOf(values));\n        if (valueIsNull != null) {\n            consumer.accept(valueIsNull, sizeOf(valueIsNull));\n        }\n        consumer.accept(this, INSTANCE_SIZE);\n    }\n\n    @Override\n    public int getPositionCount()\n    {\n        return positionCount;\n    }\n\n    @Override\n    public long getLong(int position, int offset)\n    {\n        checkReadablePosition(position);\n        if (offset != 0 && offset != 8) {\n            throw new IllegalArgumentException(\"offset must be 0 or 8\");\n        }\n        return getLongUnchecked(position + positionOffset, offset);\n    }\n\n    /**\n     * Get the Slice starting at {@code this.positionOffset + offset} in the value at {@code position} with {@code length} bytes.\n     *\n     * @param position The logical position of the 128-bit integer in the values array.\n     *                 For example, position = 0 refers to the 128-bit integer at values[2] and values[3] if this.positionOffset = 1.\n     * @param offset The offset to the position in the unit of 128-bit integers.\n     *               For example, offset = 1 means the next position (one 128-bit integer or 16 bytes) to the specified position.\n     *               This means we always compare bytes starting at 128-bit integer boundaries.\n     * @param length The length in bytes. It has to be a multiple of 16.\n     */\n    @Override\n    public Slice getSlice(int position, int offset, int length)\n    {\n        checkValidRegion(positionCount, offset, length / SIZE_OF_LONG / 2);","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlock.java#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlong value = block.getLong(position, offset); // offset arbitrary\n// after\ncheckArgument(offset == 0 || offset == 8, \"INT128 supports offsets 0/8 only, got %s\", offset);\nlong value = block.getLong(position, offset);","handlingStrategy":"type-guard","validationCode":"if (type instanceof DecimalType && ((DecimalType) type).isShortNotUsed()) {\n    checkArgument(offset == 0 || offset == 8, \"INT128 getLong supports offsets 0/8 only, got %s\", offset);\n}","typeGuard":"boolean isInt128SafeOffset(int offset) { return offset == 0 || offset == 8; }","tryCatchPattern":"try {\n    value = block.getLong(position, offset);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"offset must be 0 or 8\")) {\n        throw new IllegalStateException(\"generic 8-byte read applied to 128-bit column at offset \" + offset, e);\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["presto","block","int128","illegal-argument"],"backgroundTag":"invalid-field-offset","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}