{"record":{"id":"96bc19376deb8de6","repo":"apache/hadoop","slug":"missing-96bc19","errorCode":null,"errorMessage":"Missing ')'","messagePattern":"Missing '\\)'","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/mapreduce/lib/join/Parser.java","lineNumber":563,"sourceCode":"      CompositeInputFormat.JOIN_COMPARATOR, null, WritableComparator.class);\n    Lexer lex = new Lexer(expr);\n    Stack<Token> st = new Stack<Token>();\n    Token tok;\n    while ((tok = lex.next()) != null) {\n      if (TType.RPAREN.equals(tok.getType())) {\n        st.push(reduce(st, conf));\n      } else {\n        st.push(tok);\n      }\n    }\n    if (st.size() == 1 && TType.CIF.equals(st.peek().getType())) {\n      Node ret = st.pop().getNode();\n      if (cmpcl != null) {\n        ret.setKeyComparator(cmpcl);\n      }\n      return ret;\n    }\n    throw new IOException(\"Missing ')'\");\n  }\n\n}\n","sourceCodeStart":545,"sourceCodeEnd":567,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/join/Parser.java#L545-L567","documentation":"After tokenizing the whole join expression, Parser.parse (Parser.java:549-564) succeeds only if the stack reduces to exactly one composite node (TType.CIF token). 'Missing \\')\\'' is the catch-all failure when the residual stack is not a single node — most commonly an unclosed operator call, but also any leftover or malformed tokens.","triggerScenarios":"Unbalanced expression with a missing closing paren: 'inner(tbl(fmt,\"/a\"), tbl(fmt,\"/b\")' — reduce never fires for the outer call, leaving multiple tokens on the stack; extra tokens after a complete expression 'inner(...) tbl(...)'; an expression that reduces to a lone tbl node without an enclosing join operator (stack holds a non-CIF-reducible state per the strict final check).","commonSituations":"Hand-built mapreduce.join.expr strings with an omitted closer; line concatenation where the final ')' line is dropped; editing long expressions and deleting a paren; forgetting that the outermost call must be a composite operator around tbl nodes.","solutions":["Close every opened parenthesis — count and match '(' vs ')'","Wrap bare tbl(...) fragments in an operator: inner(tbl(...)) not just tbl(...)","Build the expression with CompositeInputFormat.compose(op, infClass, paths...) which always closes correctly","Validate early: Parser.parse(expr, conf) in a unit test; also assert expr.chars().filter(c -> c=='(').count() == expr.chars().filter(c -> c==')').count() as a cheap smoke check"],"exampleFix":"// before\nString expr = \"inner(tbl(fmt, \\\"/a\\\"), tbl(fmt, \\\"/b\\\")\"; // missing final ')'\n\n// after\nString expr = \"inner(tbl(fmt, \\\"/a\\\"), tbl(fmt, \\\"/b\\\"))\";","handlingStrategy":"validation","validationCode":"static void requireSingleReducibleRoot(String expr) {\n  int depth = 0;\n  for (char c : expr.toCharArray()) { if (c=='(') depth++; else if (c==')') depth--; }\n  if (depth != 0) throw new IllegalArgumentException(\"Missing ')' in join expression (unclosed operator)\");\n  if (!expr.matches(\"^(inner|outer|override)\\\\(.*\\\\)$\") && !expr.contains(\"(\"))\n    throw new IllegalArgumentException(\"Expression must be an operator call wrapping tbl nodes\");\n}","typeGuard":null,"tryCatchPattern":"try { Parser.parse(expr, conf); } catch (IOException e) { if (\"Missing ')'\".equals(e.getMessage())) throw new IllegalArgumentException(\"Unclosed or malformed join expression: \" + expr, e); throw e; }","preventionTips":["Close every operator call; count '(' vs ')'","Ensure the outermost element is a composite operator wrapping tbl nodes","Use compose() which always emits balanced output"],"tags":["hadoop","mapreduce","join","parser","parentheses"],"backgroundTag":"unbalanced-parentheses","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}