apache/beam · error · RuntimeException
Cannot select a subfield of a non-composite type.
Error message
Cannot select a subfield of a non-composite type.
What it means
AddFields.getAddFieldsInformation recursively computes the output type when adding fields to a nested schema. When it reaches a type that has no composite structure (not ARRAY, ITERABLE, MAP, or ROW), there is no subfield to descend into, so it throws a RuntimeException from the switch's default branch.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/transforms/AddFields.java:340
fieldType = Schema.FieldType.array(addFieldsInformation.getOutputFieldType());
break;
case ITERABLE:
addFieldsInformation =
getAddFieldsInformation(inputFieldType.getCollectionElementType(), nestedFields);
fieldType = Schema.FieldType.iterable(addFieldsInformation.getOutputFieldType());
break;
case MAP:
addFieldsInformation =
getAddFieldsInformation(inputFieldType.getMapValueType(), nestedFields);
fieldType =
Schema.FieldType.map(
inputFieldType.getMapKeyType(), addFieldsInformation.getOutputFieldType());
break;
default:
throw new RuntimeException("Cannot select a subfield of a non-composite type.");
}
fieldType = fieldType.withNullable(inputFieldType.getNullable());
return addFieldsInformation.toBuilder().setOutputFieldType(fieldType).build();
}
private static Row fillNewFields(Row row, AddFieldsInformation addFieldsInformation) {
Schema outputSchema = checkNotNull(addFieldsInformation.getOutputFieldType().getRowSchema());
List<Object> newValues = Lists.newArrayListWithCapacity(outputSchema.getFieldCount());
for (int i = 0; i < row.getFieldCount(); ++i) {
AddFieldsInformation nested = addFieldsInformation.getNestedNewValues().get(i);
if (nested != null) {
// New fields were added to nested subfields of this value. Recursively fill them out
// before adding to the new row.
Object newValue = fillNewFields(row.getValue(i), nested.getOutputFieldType(), nested);
newValues.add(newValue);
} else {
// Nothing changed. Just copy the old value into the new row.View on GitHub (pinned to 12126d8942)
Solutions
- Correct the field path so it only descends through composite (ROW/MAP/ARRAY) types.
- Verify the input schema with pcollection.getSchema() and confirm the parent field is a ROW/MAP/ARRAY before adding a nested field.
- If you want to add a top-level field, use a non-nested name like 'a_b' instead of 'a.b'.
- Wrap the transform application in a try-catch for RuntimeException if schemas are dynamic, and fail gracefully.
Example fix
// before (a is a STRING field)
PCollection<Row> out = rows.apply(AddFields.<Row>field("a.b", FieldType.STRING));
// after
PCollection<Row> out = rows.apply(AddFields.<Row>field("a_row.b", FieldType.STRING)); Defensive patterns
Strategy: validation
Validate before calling
Schema schema = pc.getSchema();
Schema.Field f = schema.getField("a");
TypeName tn = f.getType().getTypeName();
if (!EnumSet.of(TypeName.ROW, TypeName.MAP, TypeName.ARRAY, TypeName.ITERABLE).contains(tn)) {
throw new IllegalStateException("cannot descend into non-composite field 'a'");
} Type guard
static boolean isComposite(Schema.Field f) {
switch (f.getType().getTypeName()) {
case ROW: case MAP: case ARRAY: case ITERABLE: return true;
default: return false;
}
} Try / catch
try { out = pc.apply(AddFields.<Row>field(path, type)); } catch (RuntimeException e) { if (e.getMessage().contains("non-composite")) { /* fix path or skip */ } else throw e; } Prevention
- Validate nested field paths against the actual schema before applying AddFields
- Re-derive schemas after upstream schema-evolving transforms
- Prefer flat field names over dotted paths when the parent is scalar
When it happens
Trigger: Calling AddFields.<FieldName> or AddFields.field with a field path that traverses INTO a scalar leaf type, e.g. adding 'a.b' where field 'a' is a STRING or INT64 rather than a ROW/MAP/ARRAY.
Common situations: Typos in nested field paths (intending 'a.b' on a row schema but 'a' is actually scalar), or schemas changed upstream so a formerly-ROW field became a primitive, making the path invalid.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- We currently only support wildcards at terminal parts of sel
- Unexpected field type
- '%s' does not support nested fields: %s
- Timing number 0b" + timingNumber.toString(2) + " has more th
- No proto encoding for PaneInfoCoder, always part of Windowed
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/91587910ec9ed905.
Report an issue: GitHub.