apache/beam · error · IllegalStateException
Subclass of class org.apache.beam.sdk.transforms.CombineFn m
Error message
Subclass of class org.apache.beam.sdk.transforms.CombineFn must be parameterized to be used as a UDAF
What it means
Beam SQL walks the UDAF's class hierarchy up to CombineFn and requires that the direct CombineFn superclass be a parameterized type, because the type parameters (InputT, AccumT, OutputT) are how SQL types are inferred. A subclass that extends CombineFn raw (or via a non-parameterized chain) gives no type information at runtime due to erasure, so the UDAF cannot be built.
Source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/UdafImpl.java:127
}
ParameterizedType parameterizedType = findCombineFnSuperClass();
return parameterizedType.getActualTypeArguments()[0];
}
protected Type getOutputType() {
return combineFn.getOutputType().getType();
}
private ParameterizedType findCombineFnSuperClass() {
Class clazz = combineFn.getClass();
while (!clazz.getSuperclass().equals(CombineFn.class)) {
clazz = clazz.getSuperclass();
}
if (!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {
throw new IllegalStateException(
"Subclass of " + CombineFn.class + " must be parameterized to be used as a UDAF");
}
return (ParameterizedType) clazz.getGenericSuperclass();
}
}
View on GitHub (pinned to 12126d8942)
Solutions
- Parameterize the CombineFn subclass explicitly: class MySumFn extends CombineFn<Long, long[], Long> instead of raw extends CombineFn
- Ensure every class in the hierarchy between your UDAF and CombineFn propagates concrete type parameters
- Verify with clazz.getGenericSuperclass() instanceof ParameterizedType before registering
Example fix
// before
class MySumFn extends CombineFn { ... }
// after
class MySumFn extends CombineFn<Long, long[], Long> { ... } Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = myFn.getClass(); while (c != null && !c.getSuperclass().equals(CombineFn.class)) c = c.getSuperclass(); boolean ok = c != null && c.getGenericSuperclass() instanceof ParameterizedType;
Type guard
static boolean isParameterizedCombineFn(Class<?> clazz) {
while (clazz != null && !clazz.getSuperclass().equals(CombineFn.class)) clazz = clazz.getSuperclass();
return clazz != null && clazz.getGenericSuperclass() instanceof ParameterizedType;
} Try / catch
try {
sqlEnv.registerUdaf(name, myFn);
} catch (IllegalStateException e) {
if (e.getMessage().contains("must be parameterized")) {
throw new IllegalStateException("Add <InputT, AccumT, OutputT> to 'extends CombineFn<...>' in " + myFn.getClass().getName(), e);
} else throw e;
} Prevention
- Never extend CombineFn as a raw type; always supply <InputT, AccumT, OutputT>
- Keep intermediate subclasses generic-pass-through with concrete parameters
- Add a reflection-based registration test that checks getGenericSuperclass() instanceof ParameterizedType
When it happens
Trigger: Registering a UDAF whose class hierarchy reaches CombineFn through a raw (non-generic) extends clause, e.g. class MyFn extends CombineFn, or an intermediate generic subclass instantiated without type arguments.
Common situations: Migrating legacy CombineFns written with raw types; defining CombineFn subclasses inside generic classes where the extends clause loses parameterization; copy-pasting a CombineFn but dropping the <...> type arguments.
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
- Cannot get type arguments for %s: must implement parameteriz
- Unable to infer SQL type from type variable . This usually m
- Cannot infer coder for type parameter
- is not a ParameterizedType
- Cannot encode elements of type %s with coder %s: the generic
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/7629c7da1cd44c3c.
Report an issue: GitHub.