{"record":{"id":"ecc9788f324dc4df","repo":"apache/hadoop","slug":"expected-numtype","errorCode":null,"errorMessage":"Expected numtype","messagePattern":"Expected numtype","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/mapred/join/Parser.java","lineNumber":91,"sourceCode":"   * Tagged-union type for tokens from the join expression.\n   * @see Parser.TType\n   */\n  @InterfaceAudience.Public\n  @InterfaceStability.Evolving\n  public static class Token {\n\n    private TType type;\n\n    Token(TType type) {\n      this.type = type;\n    }\n\n    public TType getType() { return type; }\n    public Node getNode() throws IOException {\n      throw new IOException(\"Expected nodetype\");\n    }\n    public double getNum() throws IOException {\n      throw new IOException(\"Expected numtype\");\n    }\n    public String getStr() throws IOException {\n      throw new IOException(\"Expected strtype\");\n    }\n  }\n\n  @InterfaceAudience.Public\n  @InterfaceStability.Evolving\n  public static class NumToken extends Token {\n    private double num;\n    public NumToken(double num) {\n      super(TType.NUM);\n      this.num = num;\n    }\n    public double getNum() { return num; }\n  }\n\n  @InterfaceAudience.Public","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java#L73-L109","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before (custom Node.parse)\ndouble v = t.getNum(); // throws Expected numtype on non-numeric arg\n\n// after\nif (!Parser.TType.NUM.equals(t.getType())) {\n  throw new IOException(\"numeric argument expected, got \" + t.getType());\n}\ndouble v = t.getNum();","handlingStrategy":"type-guard","validationCode":"// in a custom Node.parse, before reading a numeric formal\nfor (Token t : args) {\n  if (Parser.TType.NUM.equals(t.getType())) {\n    double v = t.getNum();\n  } else {\n    throw new IOException(\"numeric argument expected, got \" + t.getType());\n  }\n}","typeGuard":"boolean isNumToken(Parser.Token t) {\n  return Parser.TType.NUM.equals(t.getType());\n}","tryCatchPattern":"try {\n  new CompositeInputFormat<Object>().setFormat(job);\n} catch (IOException e) {\n  throw new IllegalArgumentException(\"join expression formals do not match the custom node\", e);\n}","preventionTips":["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"],"tags":["hadoop","mapreduce","join","parser","token","extension"],"backgroundTag":"expression-parse-error","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}