apache/beam · error · IllegalArgumentException
Expected thrift class but got
Error message
Expected thrift class but got: %s
What it means
ThriftSchema.schemaFor builds a Beam Schema from a thrift class but first requires the target class to implement TBase. If a non-thrift class is passed, an IllegalArgumentException with this message is thrown.
Solutions
- Pass a class generated by the thrift compiler (extends TBase), e.g. com.example.thrift.ThriftRecord
- Check the generic/raw type being forwarded — schemaFor(getRawType()) may be receiving Object or a wrapper
- If the element type should be a POJO, use the standard Schema inference instead of ThriftSchema
Example fix
// before Schema s = ThriftSchema.provider().schemaFor(TypeDescriptor.of(MyPojo.class)); // not TBase // after Schema s = ThriftSchema.provider().schemaFor(TypeDescriptor.of(com.example.thrift.ThriftRecord.class));
Defensive patterns
Strategy: type-guard
Validate before calling
if (!TBase.class.isAssignableFrom(ThriftRecord.class)) { throw new IllegalArgumentException("element type must be a thrift-generated TBase"); } Type guard
static <T> boolean isThriftType(Class<T> c) { return TBase.class.isAssignableFrom(c); } Try / catch
try { schema = ThriftSchema.provider().schemaFor(td); } catch (IllegalArgumentException e) { throw new IllegalStateException("Pass a thrift-generated class, not " + td.getRawType(), e); } Prevention
- Type transforms as PCollection<? extends TBase> so misuse is caught at compile time
- Avoid raw TypeDescriptor.of(Object.class) forwarding
- Use the standard schema framework for non-thrift POJOs
When it happens
Trigger: Passing a TypeDescriptor or Class that is not a generated thrift struct (e.g. a plain POJO or the wrong type parameter) to ThriftSchema.provider().schemaFor(...) or a ThriftIO transform expecting a thrift class.
Common situations: Refactoring pipeline types and accidentally wiring a POJO where a generated thrift struct belongs; using the raw generic type instead of the concrete TBase subclass.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Could not infer beam type for thrift field
- Given message schema
- The parameter list: does not match the expected fields
- Arrow schema conversion does not support Beam type
- Cannot call getFromRowFunction when there is no schema
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/328a7acfeb8499fc.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/thrift/src/main/java/org/apache/beam/sdk/io/thrift/ThriftSchema.java:173
}
public @NonNull SchemaProvider provider() {
if (typedefs.isEmpty()) {
return defaultProvider;
} else {
return new ThriftSchema(unmodifiableMap(new HashMap<>(typedefs)));
}
}
}
@Override
public <T> @NonNull Schema schemaFor(TypeDescriptor<T> typeDescriptor) {
return schemaFor(typeDescriptor.getRawType());
}
private Schema schemaFor(Class<?> targetClass) {
if (!TBase.class.isAssignableFrom(targetClass)) {
throw new IllegalArgumentException("Expected thrift class but got: " + targetClass);
}
final Stream<Schema.Field> fields =
thriftFieldDescriptors(targetClass).values().stream().map(this::beamField);
if (TUnion.class.isAssignableFrom(targetClass)) {
// Beam OneOf is just a record of fields where exactly one must be non-null, so it doesn't
// allow the types of the cases to be nullable
return OneOfType.create(fields.map(f -> f.withNullable(false)).collect(Collectors.toList()))
.getOneOfSchema();
} else {
return fields
.reduce(Schema.builder(), Schema.Builder::addField, ThriftSchema::throwingCombiner)
.build();
}
}
private static <X> X throwingCombiner(X lhs, X rhs) {
throw new IllegalStateException();
}View on GitHub (pinned to 12126d8942)