{"record":{"id":"c7730c088f3e99e1","repo":"apache/flink","slug":"tuple-needs-to-be-parameterized-by-using-generics","errorCode":null,"errorMessage":"Tuple needs to be parameterized by using generics.","messagePattern":"Tuple needs to be parameterized by using generics\\.","errorType":"exception","errorClass":"InvalidTypesException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java","lineNumber":915,"sourceCode":"                        \"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<?>) {\n                throw new InvalidTypesException(\n                        \"Tuple needs to be parameterized by using generics.\");\n            }\n\n            typeHierarchyForSubtypes.add(curT);\n\n            // create the type information for the subtypes\n            final TypeInformation<?>[] subTypesInfo =\n                    createSubTypesInfo(\n                            t,\n                            (ParameterizedType) curT,\n                            typeHierarchyForSubtypes,\n                            in1Type,\n                            in2Type,\n                            false);\n            // type needs to be treated a pojo due to additional fields\n            if (subTypesInfo == null) {\n                return analyzePojo(t, new ArrayList<>(typeHierarchy), in1Type, in2Type);\n            }","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java#L897-L933","documentation":"Thrown when Flink's TypeExtractor encounters a Tuple subclass that is used as a raw type without type parameters. The extractor walks the class hierarchy up to the immediate child of Tuple and checks whether that child is a ParameterizedType; if it is a plain Class instead, the generic field types of the tuple have been erased and cannot be recovered. This makes serialization and state management impossible, so extraction fails.","triggerScenarios":"A subclass of Tuple (Tuple1–Tuple25) is used as a raw type — e.g. `class MyTuple extends Tuple2` without `<String,Integer>`. Occurs when a function returns or accepts a non-generic Tuple subclass, or when a Tuple subclass is defined without specifying its field types on the extends clause.","commonSituations":"Defining a custom Tuple subclass like `class Event extends Tuple2 {}` instead of `class Event extends Tuple2<String,Long> {}`. Using a raw Tuple subclass as a MapFunction output type. Subclassing a Tuple in legacy Java code that suppresses generics.","solutions":["Parameterize the Tuple subclass with explicit field types: `class Event extends Tuple2<String, Long> {}`","If using the DataStream API, supply the TypeInformation explicitly via `.returns(TypeInformation.of(new TypeHint<Tuple2<String,Long>>(){}))`","Implement ResultTypeQueryable on the function and override getProducedType() to return the TypeInformation manually","Use a POJO or Row instead of a custom Tuple subclass when genericity is hard to express"],"exampleFix":"// before\nclass Event extends Tuple2 {}\n\n// after\nclass Event extends Tuple2<String, Long> {\n    public String getId() { return f0; }\n    public long getTs() { return f1; }\n}","handlingStrategy":"validation","validationCode":"// Before using a Tuple subclass, verify it is parameterized\nClass<?> tupleClass = MyTuple.class;\nType supertype = tupleClass.getGenericSuperclass();\nif (!(supertype instanceof ParameterizedType) && tupleClass != Tuple0.class) {\n    throw new IllegalArgumentException(\n        \"Tuple subclass \" + tupleClass.getName()\n        + \" must be parameterized, e.g. extends Tuple2<String, Integer>\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always specify type parameters when subclassing Tuple: `extends Tuple2<String, Long>`","Use Flink's Tuple0 for empty tuples if needed","Prefer POJOs or Row for complex data models to avoid Tuple parameterization issues","Run a quick unit test calling TypeExtractor.createTypeInfo(MyClass.class) early in development"],"tags":["type-extraction","tuple","generics","reflection"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}