{"record":{"id":"4d35b21a8677812c","repo":"apache/hadoop","slug":"identifier-expected","errorCode":null,"errorMessage":"Identifier expected","messagePattern":"Identifier expected","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java","lineNumber":466,"sourceCode":"      for (Node n : kids) {\n        sb.append(n.toString() + \",\");\n      }\n      sb.setCharAt(sb.length() - 1, ')');\n      return sb.toString();\n    }\n  }\n\n  private static Token reduce(Stack<Token> st, JobConf job) throws IOException {\n    LinkedList<Token> args = new LinkedList<Token>();\n    while (!st.isEmpty() && !TType.LPAREN.equals(st.peek().getType())) {\n      args.addFirst(st.pop());\n    }\n    if (st.isEmpty()) {\n      throw new IOException(\"Unmatched ')'\");\n    }\n    st.pop();\n    if (st.isEmpty() || !TType.IDENT.equals(st.peek().getType())) {\n      throw new IOException(\"Identifier expected\");\n    }\n    Node n = Node.forIdent(st.pop().getStr());\n    n.parse(args, job);\n    return new NodeToken(n);\n  }\n\n  /**\n   * Given an expression and an optional comparator, build a tree of\n   * InputFormats using the comparator to sort keys.\n   */\n  static Node parse(String expr, JobConf job) throws IOException {\n    if (null == expr) {\n      throw new IOException(\"Expression is null\");\n    }\n    Class<? extends WritableComparator> cmpcl =\n      job.getClass(\"mapred.join.keycomparator\", null, WritableComparator.class);\n    Lexer lex = new Lexer(expr);\n    Stack<Token> st = new Stack<Token>();","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java#L448-L484","documentation":"After popping back to '(', reduce() requires the next token down the stack to be the operator identifier (TType.IDENT). A '(' with no function name before it throws IOException(\"Identifier expected\") — the common case is wrapping the whole expression in redundant parentheses, since the grammar supports function calls only: parentheses are always calls, never grouping.","triggerScenarios":"(inner(tbl(\"a\"),tbl(\"b\"))) — outer redundant parens; a nested '(' immediately after another '(' as in inner((tbl(\"a\")),...); a quoted string or number directly before '('.","commonSituations":"Wrapping the expression in parens 'for safety'; formatting or indentation edits that insert parentheses; assuming algebraic grouping is allowed.","solutions":["Remove redundant parentheses — every '(' must directly follow an operator identifier","Nest inner calls as arguments instead of grouping them with parens","Dry-run setFormat(job) client-side"],"exampleFix":"// before\njob.set(\"mapred.join.expr\", \"(inner(tbl(F,/a),tbl(F,/b)))\");\n\n// after\njob.set(\"mapred.join.expr\", \"inner(tbl(F,/a),tbl(F,/b))\");","handlingStrategy":"validation","validationCode":"// the grammar is function calls only: every '(' must directly follow an identifier\nif (expr.matches(\".*(^|[^a-zA-Z0-9_$.])\\\\(\")) {\n  throw new IllegalArgumentException(\n      \"'(' without an operator name; remove grouping parentheses\");\n}\njob.set(\"mapred.join.expr\", expr);","typeGuard":null,"tryCatchPattern":"try {\n  new CompositeInputFormat<Object>().setFormat(job);\n} catch (IOException e) {\n  throw new IllegalArgumentException(\n      \"no grouping parens in join expressions; every '(' needs an operator name before it\", e);\n}","preventionTips":["Never wrap the expression or its sub-parts in grouping parentheses","Nest inner calls as arguments instead","Dry-run setFormat(job) for expressions produced by new config templates"],"tags":["hadoop","mapreduce","join","parser","parentheses","syntax"],"backgroundTag":"expression-parse-error","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}