prestodb/presto · error · IllegalStateException

Current entry must be closed before the block can be built

Error message

Current entry must be closed before the block can be built

What it means

RowBlockBuilder.build() materializes the final RowBlock from the accumulated field blocks and null flags. A still-open entry means the last row is incomplete: its field values have not been committed and offsets are not finalized. The library throws IllegalStateException rather than emit a partially-written row.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/RowBlockBuilder.java:251

        hasNullRow |= isNull;
        positionCount++;

        for (int i = 0; i < numFields; i++) {
            if (fieldBlockBuilders[i].getPositionCount() != fieldBlockOffsets[positionCount]) {
                throw new IllegalStateException(format("field %s has unexpected position count. Expected: %s, actual: %s", i, fieldBlockOffsets[positionCount], fieldBlockBuilders[i].getPositionCount()));
            }
        }

        if (blockBuilderStatus != null) {
            blockBuilderStatus.addBytes(Integer.BYTES + Byte.BYTES);
        }
    }

    @Override
    public Block build()
    {
        if (currentEntryOpened) {
            throw new IllegalStateException("Current entry must be closed before the block can be built");
        }
        Block[] fieldBlocks = new Block[numFields];
        for (int i = 0; i < numFields; i++) {
            fieldBlocks[i] = fieldBlockBuilders[i].build();
        }
        return createRowBlockInternal(0, positionCount, hasNullRow ? rowIsNull : null, fieldBlockOffsets, fieldBlocks);
    }

    @Override
    public String toString()
    {
        return format("RowBlockBuilder(%d){numFields=%d, positionCount=%d", hashCode(), numFields, getPositionCount());
    }

    @Override
    public BlockBuilder appendStructure(Block block)
    {
        if (!(block instanceof AbstractSingleRowBlock)) {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Call closeEntry() before build()
  2. Wrap entry building in try/finally to guarantee closeEntry()
  3. After appendStructure, remember it leaves the entry open and close it before building
  4. On abort, discard the builder instead of reusing it

Example fix

// before
rowBuilder.beginBlockEntry();
// ... write fields
Block block = rowBuilder.build(); // IllegalStateException: entry open
// after
rowBuilder.beginBlockEntry();
// ... write fields
rowBuilder.closeEntry();
Block block = rowBuilder.build();
Defensive patterns

Strategy: try-catch

Validate before calling

// track entry state yourself when wrapping the builder
class GuardedRowBuilder {
    private boolean entryOpen;
    void beforeBuild() { checkState(!entryOpen, "close the current row entry before build()"); }
}

Try / catch

try {
    return rowBuilder.build();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Current entry must be closed before the block can be built")) {
        // close the dangling entry and retry once
        rowBuilder.closeEntry();
        return rowBuilder.build();
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling build() after beginBlockEntry() without calling closeEntry(); early exception/return between beginBlockEntry and closeEntry leaving the entry open, then a later build() attempt.

Common situations: Page processors or operators that build row-typed columns and abort mid-row on exception; code that appends structure (appendStructure opens an entry) and then builds before closing.

Related errors


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