apache/flink · error · UnsupportedOperationException

Types that do not implement java.lang.Comparable cannot be u

Error message

Types that do not implement java.lang.Comparable cannot be used as keys.

What it means

Thrown by GenericTypeInfo.createComparator() when the type does not implement java.lang.Comparable. To be usable as a key, a generic type must be orderable; createComparator checks isKeyType() (which is Comparable.isAssignableFrom) and, failing that, refuses to build a comparator rather than producing a meaningless one.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/GenericTypeInfo.java:110

        return new KryoSerializer<T>(this.typeClass, config);
    }

    @SuppressWarnings("unchecked")
    @Override
    @PublicEvolving
    public TypeComparator<T> createComparator(
            boolean sortOrderAscending, ExecutionConfig executionConfig) {
        if (isKeyType()) {
            @SuppressWarnings("rawtypes")
            GenericTypeComparator comparator =
                    new GenericTypeComparator(
                            sortOrderAscending,
                            createSerializer(executionConfig.getSerializerConfig()),
                            this.typeClass);
            return (TypeComparator<T>) comparator;
        }

        throw new UnsupportedOperationException(
                "Types that do not implement java.lang.Comparable cannot be used as keys.");
    }

    // --------------------------------------------------------------------------------------------

    @Override
    public int hashCode() {
        return typeClass.hashCode();
    }

    @Override
    public boolean canEqual(Object obj) {
        return obj instanceof GenericTypeInfo;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof GenericTypeInfo) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Implement Comparable on the class used as the key.
  2. Key by a specific Comparable field (a primitive/String) instead of the whole object: keyBy(MyType::getId).
  3. Convert the type into a proper POJO with KeySelector extraction of a Comparable field.
  4. Provide a custom TypeComparator via a TypeInfoFactory if you need bespoke ordering.

Example fix

// before
DataStream<MyType> s = ...;
s.keyBy(x -> x); // MyType generic, not Comparable -> throw

// after
s.keyBy(MyType::getId); // getId returns String/Long, Comparable
// or make MyType implement Comparable<MyType>
Defensive patterns

Strategy: validation

Validate before calling

if (!Comparable.class.isAssignableFrom(MyType.class)) {
    throw new IllegalStateException("MyType must implement Comparable to be a key");
}

Type guard

static boolean isComparableKey(Class<?> c) {
    return Comparable.class.isAssignableFrom(c);
}

Prevention

When it happens

Trigger: Calling keyBy() or a sort/minBy/maxBy on a DataStream whose type is a GenericTypeInfo whose class does not implement Comparable.

Common situations: Using a custom POJO that degraded to GenericTypeInfo as a grouping/sorting key without implementing Comparable; keying by a complex object that the type system treats as generic.

Related errors


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