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

  1. Replace the Row-typed field with a concrete schema-annotated class (POJO with @DefaultSchema or AutoValue).
  2. Set the field type explicitly, e.g. FieldType.row(Schema) for the field via @SchemaField annotation or manual Schema building.
  3. Use a TypeDescriptor-based supplier with a registered schema for the Row's logical type.
  4. 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

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


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)