apache/flink · error · InvalidTypesException
Generic type '{}' or a subclass of it expected but was '{}'.
Error message
Generic type '{}' or a subclass of it expected but was '{}'. What it means
Thrown by TypeExtractor.validateInfo when a GenericTypeInfo is expected but the reflected type's class is not assignable to (i.e., is not the same class or a subclass of) the GenericTypeInfo's type class. This means the extractor expected a specific generic type or its subclass but found an incompatible class.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:1703
}
// check enum type contents
if (!(typeInfo.getTypeClass() == type)) {
throw new InvalidTypesException(
"Enum type '"
+ typeInfo.getTypeClass().getCanonicalName()
+ "' expected but was '"
+ typeToClass(type).getCanonicalName()
+ "'.");
}
}
// check for generic object
else if (typeInfo instanceof GenericTypeInfo<?>) {
Class<?> clazz = null;
if (!(isClassType(type)
&& (clazz = typeToClass(type))
.isAssignableFrom(
((GenericTypeInfo<?>) typeInfo).getTypeClass()))) {
throw new InvalidTypesException(
"Generic type '"
+ ((GenericTypeInfo<?>) typeInfo)
.getTypeClass()
.getCanonicalName()
+ "' or a subclass of it expected but was '"
+ clazz.getCanonicalName()
+ "'.");
}
}
// check for Writable
else {
validateIfWritable(typeInfo, type);
}
} else {
type = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) type);
if (!(type instanceof TypeVariable)) {
validateInfo(typeHierarchy, type, typeInfo);
}View on GitHub (pinned to 2f3c205e92)
Solutions
- Ensure the actual class is the same as or a subclass of the declared GenericTypeInfo type class.
- Provide explicit TypeInformation via .returns(TypeInformation.of(ExpectedClass.class)).
- If the class hierarchy is correct but erasure is the issue, create a concrete non-generic subclass to preserve type info.
- Verify that the generic type parameter in the function signature has the correct bound.
Example fix
// before
public class MyFunction<T> extends RichMapFunction<T, OtherClass> { ... }
// T resolves to Object due to erasure
// after
public class MyStringFunction extends RichMapFunction<String, OtherClass> { ... } Defensive patterns
Strategy: validation
Validate before calling
// Check that the actual class is a subclass of the expected generic type
Class<?> expectedClass = ((GenericTypeInfo<?>) typeInfo).getTypeClass();
Class<?> actualClass = typeToClass(type);
if (!expectedClass.isAssignableFrom(actualClass)) {
// provide correct GenericTypeInfo or concrete TypeInformation
ti = TypeInformation.of(actualClass);
} Type guard
static boolean genericTypesCompatible(GenericTypeInfo<?> expected, Type actual) {
return isClassType(actual)
&& expected.getTypeClass().isAssignableFrom(typeToClass(actual));
} Try / catch
try {
validateInfo(hierarchy, type, genericTypeInfo);
} catch (InvalidTypesException e) {
ti = TypeInformation.of(typeToClass(type));
} Prevention
- Ensure actual class is the same as or subclass of declared generic type.
- Provide explicit TypeInformation matching the concrete class.
- Create non-generic subclasses to preserve type info for the extractor.
When it happens
Trigger: Called during validateInfo when TypeInformation is a GenericTypeInfo and either the type is not a ClassType, or the resolved class is not isAssignableFrom the expected type class. Occurs when the actual class is unrelated to the declared generic type (not a subclass).
Common situations: Using a completely unrelated class where a specific generic type was expected. Type erasure resolving to Object or an unrelated class in deeply generic hierarchies. Generic base classes where the type parameter is unbounded and resolves to an unexpected class.
Related errors
- POJO type '{}' expected but was '{}'.
- Enum type '{}' expected but was '{}'.
- Object array type expected.
- Value type expected.
- Enum type expected.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/70c7463a3a3cc192.
Report an issue: GitHub.