apache/hadoop · error · IOException

Missing ')'

Error message

Missing ')'

What it means

After lexing, the whole expression must reduce to exactly one node token (TType.CIF) left on the stack. Anything else ends with IOException("Missing ')'"), the catch-all for an unbalanced or over-specified expression. Despite the message, the most common cause is an unclosed function call — e.g. inner(tbl("a"),tbl("b") — but trailing unconsumed tokens (two top-level calls, stray identifiers) produce it too.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:500

      job.getClass("mapred.join.keycomparator", null, WritableComparator.class);
    Lexer lex = new Lexer(expr);
    Stack<Token> st = new Stack<Token>();
    Token tok;
    while ((tok = lex.next()) != null) {
      if (TType.RPAREN.equals(tok.getType())) {
        st.push(reduce(st, job));
      } else {
        st.push(tok);
      }
    }
    if (st.size() == 1 && TType.CIF.equals(st.peek().getType())) {
      Node ret = st.pop().getNode();
      if (cmpcl != null) {
        ret.setKeyComparator(cmpcl);
      }
      return ret;
    }
    throw new IOException("Missing ')'");
  }

}

View on GitHub (pinned to 2add963021)

Solutions

  1. Close every '(' with exactly one ')'
  2. Keep exactly ONE top-level function call spanning all sources, nesting the rest as its arguments
  3. Generate the expression with CompositeInputFormat.compose() and dry-run setFormat(job) client-side

Example fix

// before
job.set("mapred.join.expr", "inner(tbl(F,/a),tbl(F,/b)");

// after
job.set("mapred.join.expr", "inner(tbl(F,/a),tbl(F,/b))");
Defensive patterns

Strategy: validation

Validate before calling

static void checkBalanced(String expr) {
  int depth = 0;
  boolean inQuote = false;
  for (char c : expr.toCharArray()) {
    if (c == '"') inQuote = !inQuote;
    else if (!inQuote && c == '(') depth++;
    else if (!inQuote && c == ')') depth--;
  }
  if (depth != 0) throw new IllegalArgumentException("unbalanced parentheses in join expression");
}
checkBalanced(expr);
job.set("mapred.join.expr", expr);

Try / catch

try {
  new CompositeInputFormat<Object>().setFormat(job);
} catch (IOException e) {
  throw new IllegalArgumentException(
      "expression must reduce to one top-level call; check for a missing ')' "
      + "or trailing tokens", e);
}

Prevention

When it happens

Trigger: inner(tbl("a"),tbl("b") — missing final ')'; two top-level calls concatenated like inner(...) outer(...); leftover tokens after a complete expression.

Common situations: Hand-balanced parentheses in long nested expressions; concatenating two complete expressions into one property; truncation of long expressions in XML config or shell variables.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/f1ea39062b6186db. Report an issue: GitHub.