apache/flink · error · IllegalArgumentException
Cannot set a UDF as combinable if it does not implement the
Error message
Cannot set a UDF as combinable if it does not implement the interface {} What it means
Thrown by GroupReduceOperatorBase.setCombinable(boolean) when combinable is true but the user function class does not implement the GroupCombineFunction interface. A combinable group reduce pre-reduces data using the combine phase; this requires the UDF to implement GroupCombineFunction.combine(Iterable, Collector) so the combiner can call it.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/base/GroupReduceOperatorBase.java:139
* @return The secondary order.
*/
public Ordering getGroupOrder() {
return this.groupOrder;
}
/**
* Marks the group reduce operation as combinable. Combinable operations may pre-reduce the data
* before the actual group reduce operations. Combinable user-defined functions must implement
* the interface {@link GroupCombineFunction}.
*
* @param combinable Flag to mark the group reduce operation as combinable.
*/
public void setCombinable(boolean combinable) {
// sanity check
if (combinable
&& !GroupCombineFunction.class.isAssignableFrom(
this.userFunction.getUserCodeClass())) {
throw new IllegalArgumentException(
"Cannot set a UDF as combinable if it does not implement the interface "
+ GroupCombineFunction.class.getName());
} else {
this.combinable = combinable;
}
}
/**
* Checks whether the operation is combinable.
*
* @return True, if the UDF is combinable, false if not.
* @see #setCombinable(boolean)
*/
public boolean isCombinable() {
return this.combinable;
}
public void setCustomPartitioner(Partitioner<?> customPartitioner) {View on GitHub (pinned to 2f3c205e92)
Solutions
- Make the UDF implement both GroupReduceFunction and GroupCombineFunction (or extend CombineFunction which bridges them).
- If the UDF cannot be made combinable (e.g., it needs full group context), call setCombinable(false) or do not call it.
- Use @Combinable annotation only on classes that implement GroupCombineFunction.
Example fix
// before
public static class MyReducer extends GroupReduceFunction<MyType, MyType> {
public void reduce(Iterable<MyType> values, Collector<MyType> out) { ... }
}
// elsewhere
reduceOp.setCombinable(true); // throws: MyReducer does not implement GroupCombineFunction
// after
public static class MyReducer extends RichGroupReduceFunction<MyType, MyType>
implements GroupCombineFunction<MyType, MyType> {
public void reduce(Iterable<MyType> values, Collector<MyType> out) { ... }
public void combine(Iterable<MyType> values, Collector<MyType> out) { reduce(values, out); }
}
// elsewhere
reduceOp.setCombinable(true); // ok Defensive patterns
Strategy: type-guard
Validate before calling
void safeSetCombinable(GroupReduceOperatorBase<?, ?, ?> op, boolean combinable) {
if (combinable) {
Class<?> udfClass = op.getUserFunctionWrapper().getUserCodeClass();
if (!GroupCombineFunction.class.isAssignableFrom(udfClass)) {
throw new IllegalStateException(
"UDF " + udfClass.getName() + " must implement GroupCombineFunction to be combinable");
}
}
op.setCombinable(combinable);
} Type guard
static boolean isCombinableCapable(Class<?> udfClass) {
return GroupCombineFunction.class.isAssignableFrom(udfClass);
} Try / catch
try {
reduceOp.setCombinable(true);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("GroupCombineFunction")) {
// UDF does not implement GroupCombineFunction; either implement it or disable combine
log.warn("Cannot enable combiner: {}", e.getMessage());
}
} Prevention
- Implement GroupCombineFunction on any UDF you intend to mark combinable.
- Use @Combinable annotation only on classes that implement GroupCombineFunction.
- Write a unit test asserting the UDF class is assignable from GroupCombineFunction before enabling combine.
When it happens
Trigger: Calling reduceGroup with a function that only extends GroupReduceFunction, then calling setCombinable(true) on the operator. Annotating a non-GroupCombineFunction UDF with @Combinable. The UDF class implements GroupReduceFunction but not GroupCombineFunction.
Common situations: Writing a GroupReduceFunction and wanting combiner optimization without implementing the additional GroupCombineFunction interface. Forgetting that combinable requires implementing two interfaces. Copying a reduce function that was not designed for combining and enabling combine on it.
Related errors
- Cannot use custom partitioner for a non-grouped GroupReduce
- Cannot use the key partitioner for composite keys (more than
- The filter factor cannot be smaller than zero.
- Target field {} was added twice to input {}
- The number of specified keys is different.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/0bd6b1c1e4c95e8c.
Report an issue: GitHub.