apache/flink · error · InvalidTypesException
Usage of class Tuple as a type is not allowed. Use a concret
Error message
Usage of class Tuple as a type is not allowed. Use a concrete subclass (e.g. Tuple1, Tuple2, etc.) instead.
What it means
Thrown by TypeExtractor.createTypeInfoWithTypeHierarchy when the type being analyzed is exactly Tuple.class (the abstract base class). Flink requires concrete tuple subclasses (Tuple1 through Tuple25) because the arity and field types must be known at compile time. The raw Tuple class has no fields and cannot be instantiated or serialized.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:896
private <IN1, IN2, OUT> TypeInformation<OUT> createTypeInfoWithTypeHierarchy(
List<Type> typeHierarchy,
Type t,
TypeInformation<IN1> in1Type,
TypeInformation<IN2> in2Type) {
// check if type information can be created using a type factory
final TypeInformation<OUT> typeFromFactory =
createTypeInfoFromFactory(t, typeHierarchy, in1Type, in2Type);
if (typeFromFactory != null) {
return typeFromFactory;
}
// check if type is a subclass of tuple
else if (isClassType(t) && Tuple.class.isAssignableFrom(typeToClass(t))) {
Type curT = t;
// do not allow usage of Tuple as type
if (typeToClass(t).equals(Tuple.class)) {
throw new InvalidTypesException(
"Usage of class Tuple as a type is not allowed. Use a concrete subclass (e.g. Tuple1, Tuple2, etc.) instead.");
}
// go up the hierarchy until we reach immediate child of Tuple (with or without
// generics)
// collect the types while moving up for a later top-down
List<Type> typeHierarchyForSubtypes = new ArrayList<>(typeHierarchy);
while (!(isClassType(curT) && typeToClass(curT).getSuperclass().equals(Tuple.class))) {
typeHierarchyForSubtypes.add(curT);
curT = typeToClass(curT).getGenericSuperclass();
}
if (curT == Tuple0.class) {
return new TupleTypeInfo(Tuple0.class);
}
// check if immediate child of Tuple has generics
if (curT instanceof Class<?>) {View on GitHub (pinned to 2f3c205e92)
Solutions
- Use a concrete tuple subclass: Tuple2, Tuple3, ..., Tuple25.
- Specify the concrete type using TypeInformation.of(new TypeHint<Tuple2<String,Integer>>(){}).
- If the arity is dynamic, use Row instead of Tuple.
- Ensure generic code propagates the concrete tuple subclass rather than erasing to Tuple.
Example fix
// before
public class MyMapper<T extends Tuple> implements MapFunction<String, T> { ... }
// after
public class MyMapper implements MapFunction<String, Tuple2<String, Integer>> {
public Tuple2<String, Integer> map(String s) {
return Tuple2.of(s, s.length());
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if (type.equals(Tuple.class)) {
throw new IllegalArgumentException(
"Use a concrete Tuple subclass (Tuple1..Tuple25) instead of raw Tuple");
} Type guard
static boolean isConcreteTupleType(Type t) {
return t instanceof Class<?> && Tuple.class.isAssignableFrom((Class<?>) t)
&& !t.equals(Tuple.class);
} Prevention
- Always use concrete Tuple subclasses (Tuple1 through Tuple25), never raw Tuple.
- Use Row if the number of fields is dynamic at runtime.
- Specify types with TypeInformation.of(new TypeHint<Tuple2<String,Integer>>(){}).
- Audit generic code that uses Tuple as a type bound.
When it happens
Trigger: Using Tuple.class as a type parameter: DataSet<Tuple> instead of DataSet<Tuple2<String, Integer>>. A function returning raw Tuple. A POJO field typed as Tuple without a concrete subclass. Generic code that erases Tuple2<String,Integer> to Tuple.
Common situations: Developer writes generic utilities that use Tuple as a type bound without specifying arity. Accidentally using Tuple.class in TypeInformation.of(Tuple.class). Lambda type erasure reduces Tuple2 to raw Tuple.
Related errors
- Wildcard expressions are not allowed here.
- Invalid format of tuple field expression "{}".
- The given type {} is not a parameterized type.
- The generic type parameters of '{}' are missing. In many cas
- Tuple needs to be parameterized by using generics.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/232ae614aceb9f39.
Report an issue: GitHub.