prestodb/presto · error · IllegalStateException
Current entry must be closed before a null can be written
Error message
Current entry must be closed before a null can be written
What it means
RowBlockBuilder.appendNull() adds a NULL row to the row block being built. Row entries are transactional: between beginBlockEntry() and closeEntry() the builder considers an entry 'open'. The library throws this IllegalStateException because writing a null while a nested row entry is still open would corrupt the row's field offset bookkeeping.
Source
Thrown at presto-common/src/main/java/com/facebook/presto/common/block/RowBlockBuilder.java:195
}
@Override
public BlockBuilder closeEntry()
{
if (!currentEntryOpened) {
throw new IllegalStateException("Expected entry to be opened but was closed");
}
entryAdded(false);
currentEntryOpened = false;
return this;
}
@Override
public BlockBuilder appendNull()
{
if (currentEntryOpened) {
throw new IllegalStateException("Current entry must be closed before a null can be written");
}
entryAdded(true);
return this;
}
@Override
public BlockBuilder readPositionFrom(SliceInput input)
{
boolean isNull = input.readByte() == 0;
if (isNull) {
appendNull();
}
else {
for (BlockBuilder blockBuilder : fieldBlockBuilders) {
blockBuilder.readPositionFrom(input);
}
entryAdded(false);View on GitHub (pinned to 55bb57d202)
Solutions
- Ensure every beginBlockEntry() is matched by closeEntry() before calling appendNull()
- Use try/finally around entry building so closeEntry() runs on all paths
- Restructure code to decide null-vs-value before opening the entry
- If value-vs-null is decided inside the entry, close the current entry and then call appendNull()
Example fix
// before
builder.beginBlockEntry();
if (isNull) {
builder.appendNull(); // IllegalStateException: entry still open
}
// after
if (isNull) {
builder.appendNull();
} else {
BlockBuilder entry = builder.beginBlockEntry();
// write fields...
builder.closeEntry();
} Defensive patterns
Strategy: validation
Validate before calling
// before appending null to a RowBlockBuilder
if (rowBuilder instanceof RowBlockBuilder) {
// cannot inspect private currentEntryOpened; instead structure code so appendNull
// is only called when no entry is open:
// - decide null vs value before beginBlockEntry()
// - closeEntry() in a finally block
}
Try / catch
try {
rowBuilder.appendNull();
} catch (IllegalStateException e) {
if (e.getMessage().contains("Current entry must be closed")) {
// recover: a prior entry was left open; discard builder or track open state yourself
throw new IllegalStateException("row builder misused: entry left open before appendNull", e);
}
throw e;
} Prevention
- Decide null-vs-value before opening a block entry
- Pair beginBlockEntry()/closeEntry() with try/finally
- Never return or throw from inside an open entry without closing it
- Wrap appendStructure calls with an immediate closeEntry()
When it happens
Trigger: Calling appendNull() after beginBlockEntry() without first calling closeEntry() on the row builder; also any code path (e.g. readPositionFrom or a type's read method) that appends a null while an entry opened via appendStructure/beginBlockEntry remains open.
Common situations: Custom ParametricType/BlockEncoding implementations or deserializers that begin an entry but take an early return (e.g. on a null field) before closing it; test code building nested row types that forget closeEntry() in a branch.
Related errors
- Current entry must be closed before the block can be built
- 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/eefb4ff3e66b4bb6.
Report an issue: GitHub.