apache/flink · error · RuntimeException
The type {} is not Comparable.
Error message
The type {} is not Comparable. What it means
Thrown by ValueTypeInfo.createComparator when the Value type wrapped by ValueTypeInfo is not Comparable (does not implement java.lang.Comparable). Flink needs a comparator for sorting/grouping keyed operations, and only Value types that are Comparable can serve as keys.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/ValueTypeInfo.java:201
} else if (ShortValue.class.isAssignableFrom(type)) {
return (TypeSerializer<T>) ShortValueSerializer.INSTANCE;
} else if (StringValue.class.isAssignableFrom(type)) {
return (TypeSerializer<T>) StringValueSerializer.INSTANCE;
} else if (CopyableValue.class.isAssignableFrom(type)) {
return (TypeSerializer<T>)
createCopyableValueSerializer(type.asSubclass(CopyableValue.class));
} else {
return new ValueSerializer<T>(type);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
@PublicEvolving
public TypeComparator<T> createComparator(
boolean sortOrderAscending, ExecutionConfig executionConfig) {
if (!isKeyType()) {
throw new RuntimeException("The type " + type.getName() + " is not Comparable.");
}
if (BooleanValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new BooleanValueComparator(sortOrderAscending);
} else if (ByteValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new ByteValueComparator(sortOrderAscending);
} else if (CharValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new CharValueComparator(sortOrderAscending);
} else if (DoubleValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new DoubleValueComparator(sortOrderAscending);
} else if (FloatValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new FloatValueComparator(sortOrderAscending);
} else if (IntValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new IntValueComparator(sortOrderAscending);
} else if (LongValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) new LongValueComparator(sortOrderAscending);
} else if (NullValue.class.isAssignableFrom(type)) {
return (TypeComparator<T>) NullValueComparator.getInstance();View on GitHub (pinned to 2f3c205e92)
Solutions
- Make the custom Value type implement Comparable<ValueType> (override compareTo).
- Use a KeySelector to extract a Comparable key field instead of using the Value type directly as a key.
- Switch to a Comparable Value type such as IntValue, StringValue, or a CopyableValue subclass.
- If using the type as a key is not needed, avoid calling operations that trigger comparator creation.
Example fix
// before
public class MyValue implements Value {
public void write(DataOutput out) { ... }
public void readFields(DataInput in) { ... }
// NOT Comparable -> throws when used as key
}
// after
public class MyValue implements Value, Comparable<MyValue> {
public void write(DataOutput out) { ... }
public void readFields(DataInput in) { ... }
public int compareTo(MyValue o) { return this.id - o.id; }
} Defensive patterns
Strategy: validation
Validate before calling
// Check if the Value type is Comparable before using as a key
ValueTypeInfo<?> vti = (ValueTypeInfo<?>) typeInfo;
if (!vti.isKeyType()) {
// cannot use as key; use KeySelector or switch to Comparable Value
} Type guard
static boolean isComparableValue(Class<? extends Value> valueClass) {
return Comparable.class.isAssignableFrom(valueClass);
} Try / catch
try {
TypeComparator<?> cmp = vti.createComparator(true, executionConfig);
} catch (RuntimeException e) {
if (e.getMessage().contains("not Comparable")) {
// implement Comparable or use KeySelector
} else throw e;
} Prevention
- Make custom Value types implement Comparable<ValueType> if they will be used as keys.
- Use KeySelector to extract a Comparable key instead of using a non-Comparable Value as a key.
- Use built-in Comparable Value types (IntValue, StringValue, etc.) for keyed operations.
When it happens
Trigger: Called when createComparator is invoked on a ValueTypeInfo whose type class does not implement Comparable. This happens when a custom Value type (implementing org.apache.flink.types.Value) is used as a key in groupBy, keyBy, join, or coGroup operations without implementing Comparable.
Common situations: Creating a custom Value type that implements Value (for custom serialization) but forgets to implement Comparable, then using it as a key in keyed operations. Using a Value type in a sorting or grouping context where comparability is required.
Related errors
- The type {} cannot be used as a key.
- Types that do not implement java.lang.Comparable cannot be u
- Cannot create Comparator for {typeClass.getCanonicalName()}.
- Input type of coGroup must be one of composite types or atom
- Input types of coGroup must be composite types.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/92a284e2609ceffc.
Report an issue: GitHub.