apache/hadoop · error · IOException
Unmatched ')'
Error message
Unmatched ')'
What it means
When reduce() sees ')' it pops tokens backwards until the matching '('; if the stack empties first, there is a ')' with no opening '(' and it throws IOException("Unmatched ')'"). The canonical case is one closing parenthesis too many, e.g. inner(tbl("a"),tbl("b"))).
Source
Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:462
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(ident + "(");
for (Node n : kids) {
sb.append(n.toString() + ",");
}
sb.setCharAt(sb.length() - 1, ')');
return sb.toString();
}
}
private static Token reduce(Stack<Token> st, JobConf job) throws IOException {
LinkedList<Token> args = new LinkedList<Token>();
while (!st.isEmpty() && !TType.LPAREN.equals(st.peek().getType())) {
args.addFirst(st.pop());
}
if (st.isEmpty()) {
throw new IOException("Unmatched ')'");
}
st.pop();
if (st.isEmpty() || !TType.IDENT.equals(st.peek().getType())) {
throw new IOException("Identifier expected");
}
Node n = Node.forIdent(st.pop().getStr());
n.parse(args, job);
return new NodeToken(n);
}
/**
* Given an expression and an optional comparator, build a tree of
* InputFormats using the comparator to sort keys.
*/
static Node parse(String expr, JobConf job) throws IOException {
if (null == expr) {
throw new IOException("Expression is null");
}View on GitHub (pinned to 2add963021)
Solutions
- Balance parentheses — exactly one ')' per '('
- Generate the expression with CompositeInputFormat.compose() instead of manual concatenation
- Dry-run setFormat(job) client-side to catch it before submission
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 < 0) throw new IllegalArgumentException("unmatched )");
}
if (depth != 0) throw new IllegalArgumentException("unbalanced parentheses");
}
checkBalanced(expr);
job.set("mapred.join.expr", expr); Try / catch
try {
new CompositeInputFormat<Object>().setFormat(job);
} catch (IOException e) {
throw new IllegalArgumentException("unbalanced ')' in mapred.join.expr", e);
} Prevention
- Count parentheses when hand-writing expressions; one ')' per '('
- Prefer compose() over concatenating fragments that each add their own closer
- Run a paren-balance check on expressions built dynamically
When it happens
Trigger: An extra trailing ')'; a stray ')' anywhere no function call is currently open; expressions assembled by concatenating fragments that each carry their own closer.
Common situations: Hand-balanced parentheses; composing an expression from per-source snippets like tbl(...) + "))" where the count drifts.
Related errors
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/e8005e8b151e9d41.
Report an issue: GitHub.