prestodb/presto · error · IllegalStateException

field block builder can only be obtained before any sequenti

Error message

field block builder can only be obtained before any sequential write has done

What it means

SingleRowBlockWriter supports two mutually exclusive write modes: sequential writes (writeLong/appendStructure) or per-field block builders obtained via getFieldBlockBuilder. This library throws IllegalStateException when getFieldBlockBuilder is called after any sequential write has already started, because the writer's internal position (currentFieldIndexToWrite) has advanced and mixing modes would corrupt the row layout.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/SingleRowBlockWriter.java:55

    SingleRowBlockWriter(int rowIndex, BlockBuilder[] fieldBlockBuilders)
    {
        super(rowIndex);
        this.fieldBlockBuilders = fieldBlockBuilders;
    }

    /**
     * Obtains the field {@code BlockBuilder}.
     * <p>
     * This method is used to perform random write to {@code SingleRowBlockWriter}.
     * Each field {@code BlockBuilder} must be written EXACTLY once.
     * <p>
     * Field {@code BlockBuilder} can only be obtained before any sequential write has done.
     * Once obtained, sequential write is no longer allowed.
     */
    public BlockBuilder getFieldBlockBuilder(int fieldIndex)
    {
        if (currentFieldIndexToWrite != 0) {
            throw new IllegalStateException("field block builder can only be obtained before any sequential write has done");
        }
        fieldBlockBuilderReturned = true;
        return fieldBlockBuilders[fieldIndex];
    }

    @Override
    protected Block getRawFieldBlock(int fieldIndex)
    {
        return fieldBlockBuilders[fieldIndex];
    }

    @Override
    public long getSizeInBytes()
    {
        long size = 0;
        if (rowIndex == 0) {
            for (BlockBuilder blockBuilder : fieldBlockBuilders) {
                size += blockBuilder.getSizeInBytes();

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Obtain all field block builders via getFieldBlockBuilder BEFORE any sequential write on the row writer.
  2. Restructure the serializer to use one mode exclusively per row: either all fields via field builders, or all via sequential writes.
  3. If both modes are needed, finish the current row, build it, and start a new SingleRowBlockWriter for the next row.

Example fix

// before
writer.writeLong(0, value);
BlockBuilder field = writer.getFieldBlockBuilder(1); // throws
// after
BlockBuilder field = writer.getFieldBlockBuilder(1);
field.writeLong(value); // use field builders consistently
Defensive patterns

Strategy: validation

Validate before calling

if (writer.getCurrentFieldIndexToWrite() != 0 /* or track writes yourself */) {
    throw new IllegalStateException("must call getFieldBlockBuilder before any sequential write");
}

Try / catch

try {
    BlockBuilder f = writer.getFieldBlockBuilder(idx);
} catch (IllegalStateException e) {
    // writer already in sequential mode: rebuild the row writer
}

Prevention

When it happens

Trigger: Calling getFieldBlockBuilder(fieldIndex) on a SingleRowBlockWriter after at least one sequential write (writeByte, writeShort, writeInt, writeLong, writeBytes, appendStructure) has been performed on the same row; currentFieldIndexToWrite != 0 at call time.

Common situations: Serializers that build a row block partly with appendStructure and then try to grab individual field builders for complex types; refactored encoder code where a scalar field write was added before the nested-structure path.

Related errors


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