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

  1. Replace the unsupported property type with a supported primitive (String, Long, Double, Boolean, byte[], etc.).
  2. Register a custom FieldType/logical type or supply the schema explicitly with FieldType.logicalType / FieldType.row.
  3. Annotate the field with @SchemaField/ignore it if not needed, or convert it to a serializable representation in getters.
  4. 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

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


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)