{"record":{"id":"ab44f22e23ba7e1f","repo":"apache/flink","slug":"parameterized-tuple-type-expected","errorCode":null,"errorMessage":"Parameterized Tuple type expected.","messagePattern":"Parameterized Tuple type expected\\.","errorType":"exception","errorClass":"InvalidTypesException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java","lineNumber":1556,"sourceCode":"                if (isClassType(type) && typeToClass(type).equals(Tuple.class)) {\n                    throw new InvalidTypesException(\"Concrete subclass of Tuple expected.\");\n                }\n\n                // go up the hierarchy until we reach immediate child of Tuple (with or without\n                // generics)\n                while (!(isClassType(type)\n                        && typeToClass(type).getSuperclass().equals(Tuple.class))) {\n                    typeHierarchy.add(type);\n                    type = typeToClass(type).getGenericSuperclass();\n                }\n\n                if (type == Tuple0.class) {\n                    return;\n                }\n\n                // check if immediate child of Tuple has generics\n                if (type instanceof Class<?>) {\n                    throw new InvalidTypesException(\"Parameterized Tuple type expected.\");\n                }\n\n                TupleTypeInfo<?> tti = (TupleTypeInfo<?>) typeInfo;\n\n                Type[] subTypes = ((ParameterizedType) type).getActualTypeArguments();\n\n                if (subTypes.length != tti.getArity()) {\n                    throw new InvalidTypesException(\n                            \"Tuple arity '\"\n                                    + tti.getArity()\n                                    + \"' expected but was '\"\n                                    + subTypes.length\n                                    + \"'.\");\n                }\n\n                for (int i = 0; i < subTypes.length; i++) {\n                    validateInfo(new ArrayList<>(typeHierarchy), subTypes[i], tti.getTypeAt(i));\n                }","sourceCodeStart":1538,"sourceCodeEnd":1574,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java#L1538-L1574","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom Tuple subclasses defined without type parameters. Legacy Java code that uses raw Tuple subclasses. Tuple subclasses from libraries that suppress generics.","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"],"exampleFix":"// before — raw Tuple subclass\nclass MyKey extends Tuple2 {}\npublic class MyFunc extends MapFunction<MyKey, String> { ... }\n\n// after — parameterized\nclass MyKey extends Tuple2<String, Integer> {}\npublic class MyFunc extends MapFunction<MyKey, String> { ... }","handlingStrategy":"validation","validationCode":"// Verify Tuple subclass is parameterized\nClass<?> tupleSubclass = MyKey.class;\nType superType = tupleSubclass.getGenericSuperclass();\n// Walk up to immediate Tuple child\nwhile (superType instanceof Class<?> && !((Class<?>) superType).equals(Tuple.class)) {\n    superType = ((Class<?>) superType).getGenericSuperclass();\n}\nif (superType instanceof Class<?> && tupleSubclass != Tuple0.class) {\n    throw new IllegalStateException(\n        \"Tuple subclass \" + tupleSubclass.getName()\n        + \" is not parameterized. Use: extends Tuple2<Type1, Type2>\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["type-validation","tuple","raw-type","generics","reflection"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}