prestodb/presto · error · IllegalArgumentException

Type must be a RowType for StructVector

Error message

Type must be a RowType for StructVector

What it means

assignBlockFromStructVector converts an Arrow StructVector into a Presto row block. It requires the Presto Type to be RowType so it can access the row's field types for recursive per-field conversion; any other Type causes this IllegalArgumentException before any row is written.

Source

Thrown at presto-common-arrow/src/main/java/com/facebook/plugin/arrow/ArrowBlockBuilder.java:752

                builder.appendNull();
            }
            else {
                BlockBuilder entryBuilder = builder.beginBlockEntry();
                int entryStart = vector.getElementStartIndex(i);
                int entryEnd = vector.getElementEndIndex(i);
                for (int entryIndex = entryStart; entryIndex < entryEnd; entryIndex++) {
                    assignBlockFromValueVector(keyVector, mapType.getKeyType(), entryBuilder, entryIndex, entryIndex + 1);
                    assignBlockFromValueVector(valueVector, mapType.getValueType(), entryBuilder, entryIndex, entryIndex + 1);
                }
                builder.closeEntry();
            }
        }
    }

    public void assignBlockFromStructVector(StructVector vector, Type type, BlockBuilder builder, int startIndex, int endIndex)
    {
        if (!(type instanceof RowType)) {
            throw new IllegalArgumentException("Type must be a RowType for StructVector");
        }

        RowType rowType = (RowType) type;

        for (int i = startIndex; i < endIndex; i++) {
            if (vector.isNull(i)) {
                builder.appendNull();
            }
            else {
                BlockBuilder childBuilder = builder.beginBlockEntry();
                List<Type> childTypes = rowType.getTypeParameters();
                for (int childIndex = 0; childIndex < childTypes.size(); childIndex++) {
                    Type childType = childTypes.get(childIndex);
                    ValueVector childVector = vector.getChildByOrdinal(childIndex);
                    assignBlockFromValueVector(childVector, childType, childBuilder, i, i + 1);
                }
                builder.closeEntry();
            }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Declare the Presto column as a row (RowType) whose fields match the struct's children
  2. Correct the Type passed via assignBlockFromValueVector so the StructVector gets its RowType
  3. Ensure the number and types of RowType fields match the StructVector's child vectors

Example fix

// before
assignBlockFromStructVector(structVector, VarcharType.VARCHAR, builder, start, end);
// after
assignBlockFromStructVector(structVector, RowType.from(fieldNames, fieldTypes), builder, start, end);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(columnType instanceof RowType)) {
    throw new IllegalStateException("Column '" + name + "' must be RowType to receive StructVector, got " + columnType);
}

Type guard

boolean isRowColumn(Type type) {
    return type instanceof RowType;
}

Try / catch

try {
    builder.assignBlockFromStructVector(vector, type, blockBuilder, start, end);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("RowType for StructVector")) throw e;
    // re-derive RowType from struct children and retry
}

Prevention

When it happens

Trigger: Calling assignBlockFromStructVector (directly or via assignBlockFromValueVector) with a non-RowType, e.g. an array or map column receiving a StructVector, or a struct vector paired with a scalar type.

Common situations: Arrow schema has struct fields but the Presto table was declared with json or a flat type; nested type derivation bugs where child types leak to the parent; schema evolution adding a struct where a scalar existed before.

Related errors


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