prestodb/presto · error · IllegalStateException

"Expected entry size to be exactly " + INT128_BYTES + " byte

Error message

"Expected entry size to be exactly " + INT128_BYTES + " bytes but was " + (entryPositionCount * SIZE_OF_LONG)

What it means

Int128ArrayBuilder writes each 128-bit entry as exactly 2 longs (16 bytes) before closeEntry seals it. If entryPositionCount != 2 at closeEntry time, the entry is incomplete (not exactly 16 bytes written), so IllegalStateException is thrown to prevent writing a corrupt value into the block.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/Int128ArrayBlockBuilder.java:89

    @Override
    public BlockBuilder writeLong(long value)
    {
        if (valueIsNull.length <= positionCount) {
            growCapacity();
        }

        values[(positionCount * 2) + entryPositionCount] = value;
        entryPositionCount++;

        hasNonNullValue = true;
        return this;
    }

    @Override
    public BlockBuilder closeEntry()
    {
        if (entryPositionCount != 2) {
            throw new IllegalStateException("Expected entry size to be exactly " + INT128_BYTES + " bytes but was " + (entryPositionCount * SIZE_OF_LONG));
        }

        positionCount++;
        entryPositionCount = 0;
        if (blockBuilderStatus != null) {
            blockBuilderStatus.addBytes(Byte.BYTES + INT128_BYTES);
        }
        return this;
    }

    @Override
    public BlockBuilder appendNull()
    {
        if (valueIsNull.length <= positionCount) {
            growCapacity();
        }
        if (entryPositionCount != 0) {
            throw new IllegalStateException("Current entry must be closed before a null can be written");

View on GitHub (pinned to 55bb57d202)

Solutions

  1. For each entry write both halves: builder.writeLong(low, 0); builder.writeLong(high, 1); then closeEntry().
  2. Ensure the writer dispatches by type precision — use Int128ArrayBuilder only for values needing 16 bytes (DECIMAL(38,x)); long decimals use BigintArrayBuilder.
  3. If an entry was partially written, call resetToCurrentSize/producePage correctly instead of closeEntry; do not call closeEntry twice.

Example fix

// before
builder.writeLong(value); // only 8 bytes
builder.closeEntry(); // throws
// after
builder.writeLong(low64, 0);
builder.writeLong(high64, 1);
builder.closeEntry();
Defensive patterns

Strategy: validation

Validate before calling

// before closing, ensure exactly 16 bytes (2 longs) were written for the entry
// Int128ArrayBuilder tracks entryPositionCount internally; write both halves first
builder.writeLong(low, 0);
builder.writeLong(high, 1);
builder.closeEntry();

Type guard

boolean entryFullyWritten(int entryPositionCount) { return entryPositionCount == 2; } // 2 longs = 16 bytes

Try / catch

try {
    builder.closeEntry();
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Expected entry size to be exactly")) {
        throw new IllegalStateException("INT128 entry incomplete: write both 64-bit halves before closeEntry", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling closeEntry() on Int128ArrayBuilder after writing fewer or more than 2 longs — e.g. writing only writeLong(value, 0) without the high part, calling closeEntry twice, or a buildLongs-style loop writing one long per entry for DECIMAL(38,x).

Common situations: Generic BlockBuilder code treating INT128 like BIGINT (one writeLong then closeEntry); reset/abort paths that leave entryPositionCount in a partial state; decimal writers with wrong precision dispatch (writing 1 long for a 38-digit decimal).

Related errors


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