apache/flink · error · InvalidTypesException
The type {} cannot be used as a key.
Error message
The type {} cannot be used as a key. What it means
BasicTypeInfo.createComparator returns a TypeComparator only when comparatorClass is non-null. Some basic types (e.g., Void) have a null comparatorClass because they are not orderable, so attempting to build a comparator for them throws InvalidTypesException saying the type cannot be used as a key. This is the key-eligibility gate for basic types.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/common/typeinfo/BasicTypeInfo.java:251
@PublicEvolving
public boolean isKeyType() {
return true;
}
@Override
@PublicEvolving
public TypeSerializer<T> createSerializer(SerializerConfig serializerConfig) {
return this.serializer;
}
@Override
@PublicEvolving
public TypeComparator<T> createComparator(
boolean sortOrderAscending, ExecutionConfig executionConfig) {
if (comparatorClass != null) {
return instantiateComparator(comparatorClass, sortOrderAscending);
} else {
throw new InvalidTypesException(
"The type " + clazz.getSimpleName() + " cannot be used as a key.");
}
}
// --------------------------------------------------------------------------------------------
@Override
public int hashCode() {
return (31 * Objects.hash(clazz, serializer, comparatorClass))
+ Arrays.hashCode(possibleCastTargetTypes);
}
@Override
public boolean canEqual(Object obj) {
return obj instanceof BasicTypeInfo;
}
@OverrideView on GitHub (pinned to 2f3c205e92)
Solutions
- Choose a key field whose TypeInformation.isKeyType() returns true (orderable types like String, Integer, Long).
- Avoid keying on Void or other non-orderable basic types; restructure the pipeline to use a concrete comparable key.
- Guard generic comparator-building code with typeInfo.isKeyType() before calling createComparator.
Example fix
// before dataStream.keyBy(e -> null); // Void key -> throws // after dataStream.keyBy(Event::getId); // Long key, orderable
Defensive patterns
Strategy: type-guard
Validate before calling
TypeInformation<?> keyTi = TypeInformation.of(keyClass);
if (!keyTi.isKeyType()) {
throw new IllegalArgumentException(keyTi + " cannot be used as a key");
} Type guard
static boolean isUsableAsKey(TypeInformation<?> ti) {
return ti.isKeyType();
} Try / catch
// Prefer keyBy with a properly typed key selector; avoid catching createComparator.
// If building comparators generically:
try {
return ti.createComparator(asc, cfg);
} catch (InvalidTypesException e) {
throw new IllegalArgumentException(ti + " is not key-comparable", e);
} Prevention
- Always keyBy on orderable types (primitives, String, Date, Tuple of orderables).
- Guard generic comparator code with typeInfo.isKeyType().
- Avoid Void or non-orderable fields as keys.
When it happens
Trigger: Using a basic type with no comparator as a key (keyBy, joining, grouping, windowing on that field); calling createComparator directly on a BasicTypeInfo whose comparatorClass is null; keying a stream by a Void-typed field.
Common situations: keyBy on a field whose type resolves to a non-comparable basic type; schema changes that make a previously-keyed field nullable/void; generic code that builds comparators for arbitrary TypeInformation without checking isKeyType().
Related errors
- Could not initialize basic comparator {}
- Could not initialize comparator {}
- Could not initialize primitive {} array comparator.
- Could not initialize comparator {}
- Types that do not implement java.lang.Comparable cannot be u
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/b9e423f51a9226e1.
Report an issue: GitHub.