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
- Call closeEntry() before build()
- Wrap entry building in try/finally to guarantee closeEntry()
- After appendStructure, remember it leaves the entry open and close it before building
- 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
- Always close entries before any terminal operation (build, getRegion, appendNull)
- Use try/finally so exceptions mid-row cannot leave entries open
- Discard builders after failed entry writes instead of reusing them
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
- Current entry must be closed before a null can be written
- Invalid field position selection after nulls removed: " + se
- Current entry must be closed before a null can be written
- field %s has unexpected position count. Expected: %s, actual
- Expected current entry to be closed but was opened
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/8c27001963578628.
Report an issue: GitHub.