{"record":{"id":"c0d8ce897a40e1ab","repo":"apache/flink","slug":"this-type-ffd-gettype-cannot-be-used-as-key","errorCode":null,"errorMessage":"This type ({ffd.getType()}) cannot be used as key.","messagePattern":"This type \\((.+?)\\) cannot be used as key\\.","errorType":"exception","errorClass":"InvalidProgramException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java","lineNumber":282,"sourceCode":"\n            // extract key field types\n            CompositeType<T> cType = (CompositeType<T>) type;\n            this.keyFields = new ArrayList<>(type.getTotalFields());\n\n            // for each key position, find all (nested) field types\n            String[] fieldNames = cType.getFieldNames();\n            this.originalKeyTypes = new TypeInformation<?>[keyPositions.length];\n            ArrayList<FlatFieldDescriptor> tmpList = new ArrayList<>();\n            for (int i = 0; i < keyPositions.length; i++) {\n                int keyPos = keyPositions[i];\n                tmpList.clear();\n                // get all flat fields\n                this.originalKeyTypes[i] = cType.getTypeAt(keyPos);\n                cType.getFlatFields(fieldNames[keyPos], 0, tmpList);\n                // check if fields are of key type\n                for (FlatFieldDescriptor ffd : tmpList) {\n                    if (!ffd.getType().isKeyType()) {\n                        throw new InvalidProgramException(\n                                \"This type (\" + ffd.getType() + \") cannot be used as key.\");\n                    }\n                }\n                this.keyFields.addAll(tmpList);\n            }\n        }\n\n        /** Create String-based (nested) field expression keys on a composite type. */\n        public ExpressionKeys(String keyExpression, TypeInformation<T> type) {\n            this(new String[] {keyExpression}, type);\n        }\n\n        /** Create String-based (nested) field expression keys on a composite type. */\n        public ExpressionKeys(String[] keyExpressions, TypeInformation<T> type) {\n            checkNotNull(keyExpressions, \"Field expression cannot be null.\");\n\n            this.keyFields = new ArrayList<>(keyExpressions.length);\n","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java#L264-L300","documentation":"Thrown by ExpressionKeys(int[], TypeInformation, boolean) when a flattened key field's type fails isKeyType(). Even when the type is a valid tuple, each selected field must itself be a hashable/comparable key type; a field whose flattened type is a Map, List, Object, or a non-key composite cannot be used as a key.","triggerScenarios":"Calling groupBy(2) where tuple field 2 is a Map<String,String>; keyBy(1) where field 1 is a List; selecting a nested POJO field that is itself a non-key composite.","commonSituations":"Keying on a field that holds a collection or nested object; schema changes that turned a scalar field into a complex type; selecting a Tuple field that wraps a non-key type.","solutions":["Choose a field whose type is a valid key type (primitive, String, Date, or a Tuple/POJO of key types).","If the desired field is complex, use a KeySelector to extract a hashable sub-field.","Flatten nested structures upstream so the key field is a scalar."],"exampleFix":"// before (field 2 is Map<String,Integer>)\nds.groupBy(2);\n// after — extract a scalar via a KeySelector\nds.keyBy(e -> e.f2.get(\"tenantId\"));","handlingStrategy":"type-guard","validationCode":"for (FlatFieldDescriptor ffd : flatFields) {\n    if (!ffd.getType().isKeyType()) {\n        throw new IllegalArgumentException(\"Field type \" + ffd.getType() + \" cannot be used as key\");\n    }\n}","typeGuard":"static boolean isKeyable(TypeInformation<?> t) { return t != null && t.isKeyType(); }","tryCatchPattern":null,"preventionTips":["Key only on scalar/primitive/String/Tuple-of-key-types fields.","If the desired field is a collection or nested object, extract a scalar via a KeySelector.","Flatten nested structures upstream so the key field is hashable and comparable."],"tags":["flink-core","keys","expression-keys","type-system","validation"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}