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
- Close every '(' with exactly one ')'
- Keep exactly ONE top-level function call spanning all sources, nesting the rest as its arguments
- 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
- Keep exactly one top-level function call; nest everything else as arguments
- Close every '(' — count them when hand-editing
- Dry-run setFormat(job) client-side for every generated expression
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.