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

  1. Ensure every beginBlockEntry() is matched by closeEntry() before calling appendNull()
  2. Use try/finally around entry building so closeEntry() runs on all paths
  3. Restructure code to decide null-vs-value before opening the entry
  4. 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

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


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