apache/beam · error · IllegalArgumentException
Cannot automatically determine a field type from a Row…
Error message
Cannot automatically determine a field type from a Row class as we cannot determine the schema. You should set a field type explicitly.
What it means
FieldTypeDescriptors.fieldTypeForJavaType infers a FieldType from a Java TypeDescriptor. Row (and Row subclasses) cannot be inferred because a Row class alone doesn't identify which schema it uses, so Beam explicitly rejects it with this IllegalArgumentException rather than guessing.
Solutions
- Replace the Row-typed field with a concrete schema-annotated class (POJO with @DefaultSchema or AutoValue).
- Set the field type explicitly, e.g. FieldType.row(Schema) for the field via @SchemaField annotation or manual Schema building.
- Use a TypeDescriptor-based supplier with a registered schema for the Row's logical type.
- Catch this at schema-build time and provide FieldType.row(...) for the offending field.
Example fix
// before
public Row getPayload() { ... }
// after
@SchemaField(fieldName = "payload", fieldType = "ROW<...>") // or concrete type
public PayloadRow getPayload() { ... } // PayloadRow annotated with @DefaultSchema Defensive patterns
Strategy: validation
Validate before calling
if (Row.class.isAssignableFrom(pojo.getClass())) throw new IllegalStateException("Row fields need explicit FieldType.row(schema)"); Type guard
static <T> boolean hasRowFields(Class<T> c) {
return java.util.Arrays.stream(c.getDeclaredMethods())
.anyMatch(m -> m.getReturnType() == Row.class || Row.class.isAssignableFrom(m.getReturnType()));
} Try / catch
try { Schema.of(Pojo.class); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("from a Row class")) {
throw new IllegalStateException("Provide explicit FieldType.row(...) or use a schema-annotated class", e);
} throw e;
} Prevention
- Avoid Row/TableRow fields in schema-inferred POJOs
- Use concrete @DefaultSchema-annotated classes for nested rows
- Build schemas manually when nesting generic rows
When it happens
Trigger: Schema inference over a POJO/AutoValue class containing a property typed Row or a Row subtype, reached via getArrayFieldType/getIterableFieldType/getMapFieldType — e.g. List<Row> or a nested Row field — without an explicit FieldType.
Common situations: POJOs holding generic Row payloads; users migrating from TableRow/Row-based pipelines into typed schemas; container fields of Row without schema annotation.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Couldn't find field type for
- Beam Row schema and Iceberg schema have different…
- Cannot infer coder for type parameter
- Cannot provide a coder for a Beam Row. Please provide a…
- Failed to infer coder for DestinationT from type " +…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/012ab494a6c911b9.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/FieldTypeDescriptors.java:91
case ROW:
return TypeDescriptors.rows();
default:
return PRIMITIVE_MAPPING.get(fieldType.getTypeName());
}
}
/** Get a {@link FieldType} from a {@link TypeDescriptor}. */
public static FieldType fieldTypeForJavaType(TypeDescriptor typeDescriptor) {
// TODO: Convert for registered logical types.
if (typeDescriptor.isArray()
|| typeDescriptor.isSubtypeOf(TypeDescriptor.of(Collection.class))) {
return getArrayFieldType(typeDescriptor);
} else if (typeDescriptor.isSubtypeOf(TypeDescriptor.of(Map.class))) {
return getMapFieldType(typeDescriptor);
} else if (typeDescriptor.isSubtypeOf(TypeDescriptor.of(Iterable.class))) {
return getIterableFieldType(typeDescriptor);
} else if (typeDescriptor.isSubtypeOf(TypeDescriptor.of(Row.class))) {
throw new IllegalArgumentException(
"Cannot automatically determine a field type from a Row class"
+ " as we cannot determine the schema. You should set a field type explicitly.");
} else {
TypeName typeName = PRIMITIVE_MAPPING.inverse().get(typeDescriptor);
if (typeName == null) {
throw new RuntimeException("Couldn't find field type for " + typeDescriptor);
}
return FieldType.of(typeName);
}
}
private static FieldType getArrayFieldType(TypeDescriptor typeDescriptor) {
if (typeDescriptor.isArray()) {
if (typeDescriptor.getComponentType().getType().equals(byte.class)) {
return FieldType.BYTES;
} else {
return FieldType.array(fieldTypeForJavaType(typeDescriptor.getComponentType()));
}View on GitHub (pinned to 12126d8942)