prestodb/presto · error · IllegalArgumentException

block position count

Error message

block position count (%s) is not equal to number of fields (%s)

What it means

appendStructure copies a single-row block field-by-field into the builder, so the incoming block's position count must equal the builder's declared number of fields (numFields). A mismatch means the block's layout cannot map onto the row type, so the library throws IllegalArgumentException with both counts.

Solutions

  1. Verify block.getPositionCount() equals the row type's field count before appending
  2. Ensure the RowType/TypeSignature used to create the builder matches the block's row type
  3. Rebuild the block with the current row type if the schema changed
  4. Use row field mapping/translation code for schema evolution instead of direct append

Example fix

// before
// builder created for RowType(a, b); block has 3 fields
rowBuilder.appendStructure(block); // IllegalArgumentException: 3 != 2
// after
checkArgument(block.getPositionCount() == rowBuilder.getNumFields(), "row arity mismatch");
rowBuilder.appendStructure(block);
Defensive patterns

Strategy: validation

Validate before calling

// before appendStructure, verify arity matches the builder's row type
if (block.getPositionCount() != expectedNumFields) {
    throw new IllegalArgumentException(format(
        "row arity mismatch: block has %s fields, builder expects %s",
        block.getPositionCount(), expectedNumFields));
}

Try / catch

try {
    rowBuilder.appendStructure(block);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("is not equal to number of fields")) {
        // rebuild the row with the expected type rather than appending directly
        throw new IllegalStateException("row type of block does not match builder type; remap fields", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a single-row block built from a different row type (different arity) to appendStructure, e.g. appending a 3-field row into a 2-field row builder after a schema/type change.

Common situations: Schema evolution where a row type gained/lost fields but upstream blocks were built with the old type; dynamic row types whose field count differs across connectors or catalog versions.

Related errors


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

Appendix: source

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

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

    @Override
    public BlockBuilder appendStructure(Block block)
    {
        if (!(block instanceof AbstractSingleRowBlock)) {
            throw new IllegalStateException("Expected AbstractSingleRowBlock");
        }
        if (currentEntryOpened) {
            throw new IllegalStateException("Expected current entry to be closed but was opened");
        }
        currentEntryOpened = true;

        int blockPositionCount = block.getPositionCount();
        if (blockPositionCount != numFields) {
            throw new IllegalArgumentException(format("block position count (%s) is not equal to number of fields (%s)", blockPositionCount, numFields));
        }
        for (int i = 0; i < blockPositionCount; i++) {
            if (block.isNull(i)) {
                fieldBlockBuilders[i].appendNull();
            }
            else {
                block.writePositionTo(i, fieldBlockBuilders[i]);
            }
        }

        closeEntry();
        return this;
    }

    @Override
    public BlockBuilder appendStructureInternal(Block block, int position)
    {
        if (!(block instanceof AbstractRowBlock)) {

View on GitHub (pinned to 55bb57d202)