apache/beam · error · IllegalArgumentException
No suitable static factory method
Error message
No suitable static factory method: %s.%s(...)
What it means
For thrift union case fields, ThriftSchema.fieldValueTypeInfo looks for a static single-argument factory method on the case type whose name matches the field, is public static, takes exactly one parameter, and returns the case type. If none exists, an IllegalArgumentException of this form is thrown.
Solutions
- Regenerate the thrift classes with a thrift compiler version matching the beam-io-thrift expectations so union factory methods are emitted
- Add a public static method named after the field that accepts one parameter and returns the union case type
- Avoid hand-rolled TUnion subclasses; use thrift-compiler-generated ones
Example fix
// before
class MyUnion extends TUnion<...> { /* no static factory for field 'intValue' */ }
// after
public static MyUnion intValue(Integer value) { return new MyUnion(MyUnion._Fields.INT_VALUE, value); } Defensive patterns
Strategy: validation
Validate before calling
boolean ok = java.util.Arrays.stream(MyUnion.class.getDeclaredMethods()).anyMatch(m -> java.lang.reflect.Modifier.isPublic(m.getModifiers()) && java.lang.reflect.Modifier.isStatic(m.getModifiers()) && m.getParameterCount() == 1);
Try / catch
try { schema = ThriftSchema.provider().schemaFor(TypeDescriptor.of(MyUnion.class)); } catch (IllegalArgumentException e) { throw new IllegalStateException("Union case lacks static factory; regenerate thrift classes", e); } Prevention
- Always use thrift-compiler-generated unions
- Use the same thrift compiler version as the beam-io-thrift build expects
- Add a unit test that infers schemas for every union type
When it happens
Trigger: Building a schema for a TUnion subclass whose case field type lacks the expected static factory method (the generated fromFieldName-style method), usually because classes were generated with a different thrift compiler version or options.
Common situations: Regenerating unions with a thrift compiler that doesn't emit the factory methods; hand-written classes mimicking unions without the static factories; mixed thrift runtime/generator version mismatch.
Related errors
- Overloaded factory methods
- Incorrect thrift protocol factory class provided
- The parameter list: does not match the expected fields
- A method marked with SchemaCreate in class
- AutoValue builder class
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ba2d4c9782d0a4e5.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/thrift/src/main/java/org/apache/beam/sdk/io/thrift/ThriftSchema.java:246
}
@SuppressWarnings("unchecked")
private static <FieldT extends TFieldIdEnum, T extends TBase<T, FieldT>>
Map<FieldT, FieldMetaData> thriftFieldDescriptors(Class<?> targetClass) {
return (Map<FieldT, FieldMetaData>) FieldMetaData.getStructMetaDataMap((Class<T>) targetClass);
}
private FieldValueTypeInformation fieldValueTypeInfo(Class<?> type, String fieldName) {
if (TUnion.class.isAssignableFrom(type)) {
final List<Method> factoryMethods =
Stream.of(type.getDeclaredMethods())
.filter(m -> m.getName().equals(fieldName))
.filter(m -> m.getModifiers() == (Modifier.PUBLIC | Modifier.STATIC))
.filter(m -> m.getParameterCount() == 1)
.filter(m -> m.getReturnType() == type)
.collect(Collectors.toList());
if (factoryMethods.isEmpty()) {
throw new IllegalArgumentException(
String.format(
"No suitable static factory method: %s.%s(...)", type.getName(), fieldName));
}
if (factoryMethods.size() > 1) {
throw new IllegalStateException("Overloaded factory methods: " + factoryMethods);
}
return FieldValueTypeInformation.forSetter(
TypeDescriptor.of(type), factoryMethods.get(0), "");
} else {
try {
return FieldValueTypeInformation.forField(
TypeDescriptor.of(type), type.getDeclaredField(fieldName), 0);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException(e);
}
}
}
View on GitHub (pinned to 12126d8942)