apache/beam · error · IllegalStateException
Unknown type of CombineFn
Error message
Unknown type of CombineFn: %s
What it means
Combine.PerKeyWithHotKeyFanout wraps either a CombineFn or a KeyedCombineFn to split hot keys; when the typed function is neither, expand throws IllegalStateException reporting the unexpected CombineFn type.
Solutions
- Pass a CombineFn or KeyedCombineFn instance to withHotKeyFanout
- Check the class of the fn in the error message and align it with CombineFn/KeyedCombineFn
- Use Combine.perKey(fn).withHotKeyFanout(...) rather than composing custom wrapper types
Example fix
// before .withHotKeyFanout(myRandomFunction) // not a CombineFn // after .withHotKeyFanout((CombineFn<InputT, AccumT, OutputT>) myCombineFn)
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(fn instanceof CombineFn) && !(fn instanceof KeyedCombineFn)) {
throw new IllegalArgumentException("withHotKeyFanout requires CombineFn or KeyedCombineFn, got " + fn.getClass());
} Type guard
boolean isSupportedCombineFn(Object fn) {
return fn instanceof CombineFn || fn instanceof KeyedCombineFn;
} Try / catch
try {
return pc.apply(Combine.perKey(fn).withHotKeyFanout(hotKeyFn));
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("Unknown type of CombineFn")) {
LOG.error("Wrap the fn as a CombineFn or KeyedCombineFn; got: " + e.getMessage(), e);
}
throw e;
} Prevention
- Only pass CombineFn or KeyedCombineFn instances to withHotKeyFanout
- Avoid ad-hoc wrapper classes around combine functions
- Add a unit test expanding the transform with the actual fn instance
When it happens
Trigger: Calling withHotKeyFanout(...) with a fn object that is neither a CombineFn nor a KeyedCombineFn (e.g. a wrongly-typed custom class or a lambda cast to an unexpected interface).
Common situations: Passing a SimpleFunction or other transform fn by mistake; refactors changing a fn's base class; generic type erasure letting the wrong class reach the else branch.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Bounded Source is not BigQueryStorageStreamSource, unable…
- Can't cast non-numeric types: +input
- Can't cast numbers to non-numeric type: +output
- cannot call getPipelineOptions() in a null context
- cannot call sideInput() in a null context
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/99b0002821379377.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/Combine.java:1910
CoderRegistry registry, Coder<InputOrAccum<InputT, AccumT>> accumulatorCoder)
throws CannotProvideCoderException {
return fnWithContext.getDefaultOutputCoder(registry, inputCoder.getValueCoder());
}
@Override
public Coder<AccumT> getAccumulatorCoder(
CoderRegistry registry, Coder<InputOrAccum<InputT, AccumT>> inputCoder)
throws CannotProvideCoderException {
return accumCoder;
}
@Override
public void populateDisplayData(DisplayData.Builder builder) {
builder.delegate(PerKeyWithHotKeyFanout.this);
}
};
} else {
throw new IllegalStateException(
String.format("Unknown type of CombineFn: %s", typedFn.getClass()));
}
// Use the provided hotKeyFanout fn to split into "hot" and "cold" keys,
// augmenting the hot keys with a nonce.
final TupleTag<KV<KV<K, Integer>, InputT>> hot = new TupleTag<>();
final TupleTag<KV<K, InputT>> cold = new TupleTag<>();
PCollectionTuple split =
input.apply(
"AddNonce",
ParDo.of(
new DoFn<KV<K, InputT>, KV<K, InputT>>() {
transient int nonce;
@StartBundle
public void startBundle() {
// Spreading a hot key across all possible sub-keys for all bundles
// would defeat the goal of not overwhelming downstream reducersView on GitHub (pinned to 12126d8942)