{"record":{"id":"e2ac5948e1e9d8d0","repo":"apache/flink","slug":"field-expression-must-be-equal-to-or-for-n","errorCode":null,"errorMessage":"Field expression must be equal to '*' or '_' for non-composite types.","messagePattern":"Field expression must be equal to '\\*' or '_' for non-composite types\\.","errorType":"exception","errorClass":"InvalidProgramException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java","lineNumber":357,"sourceCode":"                    }\n                }\n            } else {\n                if (!type.isKeyType()) {\n                    throw new InvalidProgramException(\n                            \"This type (\" + type + \") cannot be used as key.\");\n                }\n\n                // check that all key expressions are valid\n                for (String keyExpr : keyExpressions) {\n                    if (keyExpr == null) {\n                        throw new InvalidProgramException(\"Expression key may not be null.\");\n                    }\n                    // strip off whitespace\n                    keyExpr = keyExpr.trim();\n                    // check that full type is addressed\n                    if (!(SELECT_ALL_CHAR.equals(keyExpr)\n                            || SELECT_ALL_CHAR_SCALA.equals(keyExpr))) {\n                        throw new InvalidProgramException(\n                                \"Field expression must be equal to '\"\n                                        + SELECT_ALL_CHAR\n                                        + \"' or '\"\n                                        + SELECT_ALL_CHAR_SCALA\n                                        + \"' for non-composite types.\");\n                    }\n                    // add full type as key\n                    keyFields.add(new FlatFieldDescriptor(0, type));\n                }\n                this.originalKeyTypes = new TypeInformation[] {type};\n            }\n        }\n\n        @Override\n        public int getNumberOfKeyFields() {\n            if (keyFields == null) {\n                return 0;\n            }","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java#L339-L375","documentation":"Thrown by Keys.ExpressionKeys(String[], TypeInformation) in the non-composite branch. For atomic (non-composite) types the only legal field expression is the select-all wildcard '*' (Java) or '_' (Scala), meaning 'use the entire value as the key'. Any other string expression is meaningless because there are no sub-fields to address on an atomic type.","triggerScenarios":"Calling keyBy(\"someField\") on a DataStream<String>, DataStream<Integer>, or any non-composite type. Passing a named field expression where the type has no fields.","commonSituations":"Treating a primitive/String stream like a POJO stream and naming a field that does not exist. Scala users using a Java-style '*' where '_' is idiomatic, or vice-versa (both are accepted, but a typo triggers this).","solutions":["Use keyBy(\"*\") (Java) or keyBy(\"_\") (Scala) to key on the entire atomic value.","Switch to positional keyBy (keyBy(0)) if appropriate for a tuple.","If you intended to key on a sub-field, change the stream type to a composite (POJO/Tuple/Row) first."],"exampleFix":"// before\nDataStream<String> names = ...;\nnames.keyBy(\"length\");  // String is atomic\n\n// after\nDataStream<String> names = ...;\nnames.keyBy(\"*\");  // key on the whole String value","handlingStrategy":"validation","validationCode":"if (!(type instanceof CompositeType)) {\n    for (String expr : keyExpressions) {\n        String trimmed = expr.trim();\n        if (!(\"*\".equals(trimmed) || \"_\".equals(trimmed))) {\n            throw new IllegalArgumentException(\n                \"Atomic type requires '*' or '_' as key expression, got: \" + trimmed);\n        }\n    }\n}","typeGuard":"static boolean isValidAtomicKeyExpr(String expr) {\n    String t = expr.trim();\n    return \"*\".equals(t) || \"_\".equals(t);\n}","tryCatchPattern":null,"preventionTips":["For primitive/String streams use keyBy(\"*\") or keyBy(\"_\").","Branch on type instanceof CompositeType to choose expression style.","Avoid reusing POJO field names on scalar streams."],"tags":["keys","type-system","keyby","flink-core"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}