apache/hadoop · error · IOException
Expected numtype
Error message
Expected numtype
What it means
Only NumToken, lexed from an unquoted numeric literal, carries a number; the base Token.getNum() throws IOException("Expected numtype"). The stock Parser never calls getNum(), so this guard exists for user extension: a custom Node subclass (registered via mapred.join.define.<ident> or addIdentifier) that reads a numeric formal hits it when the expression supplies an identifier, quoted string, or punctuation where the number was expected.
Source
Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:91
* Tagged-union type for tokens from the join expression.
* @see Parser.TType
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public static class Token {
private TType type;
Token(TType type) {
this.type = type;
}
public TType getType() { return type; }
public Node getNode() throws IOException {
throw new IOException("Expected nodetype");
}
public double getNum() throws IOException {
throw new IOException("Expected numtype");
}
public String getStr() throws IOException {
throw new IOException("Expected strtype");
}
}
@InterfaceAudience.Public
@InterfaceStability.Evolving
public static class NumToken extends Token {
private double num;
public NumToken(double num) {
super(TType.NUM);
this.num = num;
}
public double getNum() { return num; }
}
@InterfaceAudience.PublicView on GitHub (pinned to 2add963021)
Solutions
- In the custom node, check Parser.Token.getType() == TType.NUM (or instanceof NumToken) before calling getNum()
- Fix the expression so the numeric argument is an unquoted number literal
- Throw a descriptive error naming the expected formal instead of relying on the generic message
Example fix
// before (custom Node.parse)
double v = t.getNum(); // throws Expected numtype on non-numeric arg
// after
if (!Parser.TType.NUM.equals(t.getType())) {
throw new IOException("numeric argument expected, got " + t.getType());
}
double v = t.getNum(); Defensive patterns
Strategy: type-guard
Validate before calling
// in a custom Node.parse, before reading a numeric formal
for (Token t : args) {
if (Parser.TType.NUM.equals(t.getType())) {
double v = t.getNum();
} else {
throw new IOException("numeric argument expected, got " + t.getType());
}
} Type guard
boolean isNumToken(Parser.Token t) {
return Parser.TType.NUM.equals(t.getType());
} Try / catch
try {
new CompositeInputFormat<Object>().setFormat(job);
} catch (IOException e) {
throw new IllegalArgumentException("join expression formals do not match the custom node", e);
} Prevention
- Check TType.NUM before getNum() in extension nodes
- Document the expected formals of custom identifiers next to their mapred.join.define entry
- Keep custom-node formals and the expressions that use them under one test
When it happens
Trigger: A custom join node that calls t.getNum() on an argument token that is not TType.NUM, e.g. an expression myjoin(tbl(...), limit) where the node expects myjoin(tbl(...), 3).
Common situations: Extending the join grammar with numeric parameters (fan-in limits, coefficients) and passing an identifier or quoted value by mistake; evolving a custom node's expected formals without updating the expressions that use it.
Related errors
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/ecc9788f324dc4df.
Report an issue: GitHub.