apache/beam · error · RuntimeException
Couldn't find field type for
Error message
Couldn't find field type for <descriptor>
What it means
fieldTypeForJavaType falls back to a PRIMITIVE_MAPPING table (Java types to Beam TypeNames); if the TypeDescriptor is not in that map and is not a container, map, Row, or other handled shape, Beam cannot infer a FieldType and throws this RuntimeException. It marks an unsupported Java type in schema inference.
Solutions
- Replace the unsupported property type with a supported primitive (String, Long, Double, Boolean, byte[], etc.).
- Register a custom FieldType/logical type or supply the schema explicitly with FieldType.logicalType / FieldType.row.
- Annotate the field with @SchemaField/ignore it if not needed, or convert it to a serializable representation in getters.
- Extend FieldTypeDescriptors' mapping via a custom TypeSupplier if this type is widespread in your codebase.
Example fix
// before
public java.net.URI getUri() { ... }
// after
public String getUri() { return uri.toString(); } // or a logical type Defensive patterns
Strategy: validation
Validate before calling
for (Method m : pojoClass.getDeclaredMethods()) {
if (m.getName().startsWith("get") && !SUPPORTED.contains(m.getReturnType()))
throw new IllegalStateException("unsupported field type " + m.getReturnType());
} Type guard
static boolean isSupportedFieldType(TypeDescriptor<?> t) {
return t.isSubtypeOf(TypeDescriptor.of(Number.class)) || t.getType() == String.class
|| t.getType() == Boolean.class || t.getType() == byte[].class;
} Try / catch
try { Schema.of(Pojo.class); }
catch (RuntimeException e) {
if (e.getMessage().startsWith("Couldn't find field type for")) {
throw new IllegalStateException("Replace or register the unsupported property type", e);
} throw e;
} Prevention
- Restrict POJO fields to Beam-supported primitives and containers
- Model custom value types as logical types or convert in accessors
- Add a schema-inference smoke test for domain POJOs
When it happens
Trigger: Schema inference on a class whose property type is not a supported primitive or known container — e.g. java.math.BigDecimal without coder/typ registration, custom classes without schemas, org.joda.time.Instant-like types absent from the mapping.
Common situations: POJOs with custom value types (wrappers, third-party types); exposing library types (URI, Duration) as fields; upgrading Beam and relying on types previously mapped differently.
Related errors
- Cannot automatically determine a field type from a Row…
- Any not yet supported
- Azure credential provider type
- Cannot convert Beam type: to BigQuery type.
- Cannot infer coder for type parameter
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b224727832820c8d.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/FieldTypeDescriptors.java:97
/** 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()));
}
}
if (typeDescriptor.isSubtypeOf(TypeDescriptor.of(Collection.class))) {
TypeDescriptor<Collection<?>> collection = typeDescriptor.getSupertype(Collection.class);
if (collection.getType() instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) collection.getType();
java.lang.reflect.Type[] params = ptype.getActualTypeArguments();View on GitHub (pinned to 12126d8942)