{"record":{"id":"db3bc11d8b43273b","repo":"apache/flink","slug":"specifying-keys-via-field-positions-is-only-valid","errorCode":null,"errorMessage":"Specifying keys via field positions is only valid for tuple data types. Type: {type}","messagePattern":"Specifying keys via field positions is only valid for tuple data types\\. Type: (.+?)","errorType":"exception","errorClass":"InvalidProgramException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java","lineNumber":240,"sourceCode":"        public ExpressionKeys(TypeInformation<T> type) {\n            this(SELECT_ALL_CHAR, type);\n        }\n\n        /** Create int-based (non-nested) field position keys on a tuple type. */\n        public ExpressionKeys(int keyPosition, TypeInformation<T> type) {\n            this(new int[] {keyPosition}, type, false);\n        }\n\n        /** Create int-based (non-nested) field position keys on a tuple type. */\n        public ExpressionKeys(int[] keyPositions, TypeInformation<T> type) {\n            this(keyPositions, type, false);\n        }\n\n        /** Create int-based (non-nested) field position keys on a tuple type. */\n        public ExpressionKeys(int[] keyPositions, TypeInformation<T> type, boolean allowEmpty) {\n\n            if (!type.isTupleType() || !(type instanceof CompositeType)) {\n                throw new InvalidProgramException(\n                        \"Specifying keys via field positions is only valid \"\n                                + \"for tuple data types. Type: \"\n                                + type);\n            }\n            if (type.getArity() == 0) {\n                throw new InvalidProgramException(\n                        \"Tuple size must be greater than 0. Size: \" + type.getArity());\n            }\n            if (!allowEmpty && (keyPositions == null || keyPositions.length == 0)) {\n                throw new IllegalArgumentException(\"The grouping fields must not be empty.\");\n            }\n\n            this.keyFields = new ArrayList<>();\n\n            if (keyPositions == null || keyPositions.length == 0) {\n                // use all tuple fields as key fields\n                keyPositions = createIncrIntArray(type.getArity());\n            } else {","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java#L222-L258","documentation":"Thrown by ExpressionKeys(int[], TypeInformation, boolean) when the type is not a tuple type (or not a CompositeType). Position-based key specification like keyBy(0) / groupBy(0,1) indexes tuple fields by ordinal; non-tuple types (POJOs, primitives, Rows) have no ordinal addressing, so the request is invalid.","triggerScenarios":"Calling groupBy(0) on a POJO DataSet; keyBy(0) on a stream of a primitive/String type; passing an int key position to a Row-typed or generic-typed dataset.","commonSituations":"Switching a DataSet from Tuple to POJO without changing positional keys to field-name expressions; keying a stream of a wrapper type by position; legacy code using integer positions on non-tuple types.","solutions":["For POJOs, use field-name expressions: groupBy(\"userId\").","For atomic types, use keyBy(value -> value) or the select-all expression.","Wrap the data in a Tuple if positional access is desired."],"exampleFix":"// before (Event is a POJO)\nds.groupBy(0);\n// after\nds.groupBy(\"eventId\");","handlingStrategy":"validation","validationCode":"if (!type.isTupleType() || !(type instanceof CompositeType)) {\n    throw new IllegalArgumentException(\n        \"Position-based keys require a tuple type; got \" + type + \". Use a field-name expression for POJOs.\");\n}","typeGuard":"static <T> boolean supportsPositionKeys(TypeInformation<T> t) {\n    return t.isTupleType() && t instanceof CompositeType;\n}","tryCatchPattern":null,"preventionTips":["Use integer positions only for Tuple types; use field-name strings for POJOs.","When switching a DataSet from Tuple to POJO, convert positional keys to name expressions.","Add a helper that picks the key style based on the type's kind."],"tags":["flink-core","keys","expression-keys","tuple","type-system"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}