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

  1. Make the custom Value type implement Comparable<ValueType> (override compareTo).
  2. Use a KeySelector to extract a Comparable key field instead of using the Value type directly as a key.
  3. Switch to a Comparable Value type such as IntValue, StringValue, or a CopyableValue subclass.
  4. 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

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


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/92a284e2609ceffc. Report an issue: GitHub.