apache/flink · error · InvalidTypesException
Parameterized Tuple type expected.
Error message
Parameterized Tuple type expected.
What it means
Thrown during input type validation for Tuple types when the immediate child of Tuple in the class hierarchy is a raw Class rather than a ParameterizedType. After walking up the hierarchy to the immediate Tuple subclass, if that subclass is used without generics (e.g. `extends Tuple2` without `<String,Integer>`), the field types are erased and cannot be validated.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:1556
if (isClassType(type) && typeToClass(type).equals(Tuple.class)) {
throw new InvalidTypesException("Concrete subclass of Tuple expected.");
}
// go up the hierarchy until we reach immediate child of Tuple (with or without
// generics)
while (!(isClassType(type)
&& typeToClass(type).getSuperclass().equals(Tuple.class))) {
typeHierarchy.add(type);
type = typeToClass(type).getGenericSuperclass();
}
if (type == Tuple0.class) {
return;
}
// check if immediate child of Tuple has generics
if (type instanceof Class<?>) {
throw new InvalidTypesException("Parameterized Tuple type expected.");
}
TupleTypeInfo<?> tti = (TupleTypeInfo<?>) typeInfo;
Type[] subTypes = ((ParameterizedType) type).getActualTypeArguments();
if (subTypes.length != tti.getArity()) {
throw new InvalidTypesException(
"Tuple arity '"
+ tti.getArity()
+ "' expected but was '"
+ subTypes.length
+ "'.");
}
for (int i = 0; i < subTypes.length; i++) {
validateInfo(new ArrayList<>(typeHierarchy), subTypes[i], tti.getTypeAt(i));
}View on GitHub (pinned to 2f3c205e92)
Solutions
- Parameterize the Tuple subclass: `class MyKey extends Tuple2<String, Integer> {}`
- Use a concrete Tuple directly in the function signature instead of a raw subclass
- Provide TypeInformation explicitly via `.returns(...)` to bypass validation
Example fix
// before — raw Tuple subclass
class MyKey extends Tuple2 {}
public class MyFunc extends MapFunction<MyKey, String> { ... }
// after — parameterized
class MyKey extends Tuple2<String, Integer> {}
public class MyFunc extends MapFunction<MyKey, String> { ... } Defensive patterns
Strategy: validation
Validate before calling
// Verify Tuple subclass is parameterized
Class<?> tupleSubclass = MyKey.class;
Type superType = tupleSubclass.getGenericSuperclass();
// Walk up to immediate Tuple child
while (superType instanceof Class<?> && !((Class<?>) superType).equals(Tuple.class)) {
superType = ((Class<?>) superType).getGenericSuperclass();
}
if (superType instanceof Class<?> && tupleSubclass != Tuple0.class) {
throw new IllegalStateException(
"Tuple subclass " + tupleSubclass.getName()
+ " is not parameterized. Use: extends Tuple2<Type1, Type2>");
} Prevention
- Always specify type parameters when extending Tuple subclasses
- Use `extends Tuple2<String, Integer>` not `extends Tuple2`
- Run TypeExtractor.createTypeInfo() on custom Tuple subclasses early in development
- Prefer anonymous Tuple types or direct Tuple usage over custom subclasses
When it happens
Trigger: A function input type is a Tuple subclass that extends a Tuple without specifying type parameters — e.g. `class MyKey extends Tuple2 {}`. The validation code walks up to the immediate Tuple child and finds it is a Class (not ParameterizedType), meaning the field types have been erased.
Common situations: Custom Tuple subclasses defined without type parameters. Legacy Java code that uses raw Tuple subclasses. Tuple subclasses from libraries that suppress generics.
Related errors
- Concrete subclass of Tuple expected.
- Tuple needs to be parameterized by using generics.
- The types of the interface {} could not be inferred. Support
- Tuple type expected.
- Tuple arity '{}' expected but was '{}'.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/ab44f22e23ba7e1f.
Report an issue: GitHub.