{"record":{"id":"232ae614aceb9f39","repo":"apache/flink","slug":"usage-of-class-tuple-as-a-type-is-not-allowed-use","errorCode":null,"errorMessage":"Usage of class Tuple as a type is not allowed. Use a concrete subclass (e.g. Tuple1, Tuple2, etc.) instead.","messagePattern":"Usage of class Tuple as a type is not allowed\\. Use a concrete subclass \\(e\\.g\\. Tuple1, Tuple2, etc\\.\\) instead\\.","errorType":"exception","errorClass":"InvalidTypesException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java","lineNumber":896,"sourceCode":"    private <IN1, IN2, OUT> TypeInformation<OUT> createTypeInfoWithTypeHierarchy(\n            List<Type> typeHierarchy,\n            Type t,\n            TypeInformation<IN1> in1Type,\n            TypeInformation<IN2> in2Type) {\n\n        // check if type information can be created using a type factory\n        final TypeInformation<OUT> typeFromFactory =\n                createTypeInfoFromFactory(t, typeHierarchy, in1Type, in2Type);\n        if (typeFromFactory != null) {\n            return typeFromFactory;\n        }\n        // check if type is a subclass of tuple\n        else if (isClassType(t) && Tuple.class.isAssignableFrom(typeToClass(t))) {\n            Type curT = t;\n\n            // do not allow usage of Tuple as type\n            if (typeToClass(t).equals(Tuple.class)) {\n                throw new InvalidTypesException(\n                        \"Usage of class Tuple as a type is not allowed. Use a concrete subclass (e.g. Tuple1, Tuple2, etc.) instead.\");\n            }\n\n            // go up the hierarchy until we reach immediate child of Tuple (with or without\n            // generics)\n            // collect the types while moving up for a later top-down\n            List<Type> typeHierarchyForSubtypes = new ArrayList<>(typeHierarchy);\n            while (!(isClassType(curT) && typeToClass(curT).getSuperclass().equals(Tuple.class))) {\n                typeHierarchyForSubtypes.add(curT);\n                curT = typeToClass(curT).getGenericSuperclass();\n            }\n\n            if (curT == Tuple0.class) {\n                return new TupleTypeInfo(Tuple0.class);\n            }\n\n            // check if immediate child of Tuple has generics\n            if (curT instanceof Class<?>) {","sourceCodeStart":878,"sourceCodeEnd":914,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java#L878-L914","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npublic class MyMapper<T extends Tuple> implements MapFunction<String, T> { ... }\n// after\npublic class MyMapper implements MapFunction<String, Tuple2<String, Integer>> {\n    public Tuple2<String, Integer> map(String s) {\n        return Tuple2.of(s, s.length());\n    }\n}","handlingStrategy":"type-guard","validationCode":"if (type.equals(Tuple.class)) {\n    throw new IllegalArgumentException(\n        \"Use a concrete Tuple subclass (Tuple1..Tuple25) instead of raw Tuple\");\n}","typeGuard":"static boolean isConcreteTupleType(Type t) {\n    return t instanceof Class<?> && Tuple.class.isAssignableFrom((Class<?>) t)\n        && !t.equals(Tuple.class);\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["type-extraction","tuple","raw-type","type-erasure"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}