{"record":{"id":"49b1ad6cc275e647","repo":"apache/hadoop","slug":"expected-nodetype","errorCode":null,"errorMessage":"Expected nodetype","messagePattern":"Expected nodetype","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":88,"sourceCode":"  public enum TType { CIF, IDENT, COMMA, LPAREN, RPAREN, QUOT, NUM, }\n\n  /**\n   * 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; }","sourceCodeStart":70,"sourceCodeEnd":106,"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#L70-L106","documentation":"Parser tokens are a tagged union; only NodeToken (TType.CIF) carries a Node, and Token.getNode() on any other token throws IOException(\"Expected nodetype\"). In practice this fires inside CNode.parse (Parser.java:437) while interpreting the argument list of a composite operator (inner/outer/override or a mapred.join.define identifier): every argument must itself be a function node such as tbl(...), and a bare identifier, number, or quoted string in that position triggers the error.","triggerScenarios":"Expressions like inner(left, right) where the arguments are bare IDENT tokens instead of tbl(...) calls; outer(tbl(\"a\"), \"b\") with a quoted string argument; expressions built by string concatenation that drop the tbl(...) wrapper around a source.","commonSituations":"Hand-writing mapred.join.expr instead of using CompositeInputFormat.compose(); copying an example expression and deleting a tbl(...) wrapper while refactoring.","solutions":["Wrap every argument in a function node, normally tbl(<InputFormat class>,\\\"<path>\\\")","Build the expression programmatically with CompositeInputFormat.compose(op, InputFormat.class, paths...), which always emits well-formed arguments","Dry-run the expression client-side via new CompositeInputFormat().setFormat(job) to fail before job submission"],"exampleFix":"// before\njob.set(\"mapred.join.expr\", \"inner(left, right)\");\n\n// after\njob.set(\"mapred.join.expr\",\n    CompositeInputFormat.compose(\"inner\", SequenceFileInputFormat.class,\n        \"/join/left\", \"/join/right\"));","handlingStrategy":"validation","validationCode":"String expr = \"inner(tbl(org.apache.hadoop.mapred.SequenceFileInputFormat,\\\"/a\\\"),\"\n    + \"tbl(org.apache.hadoop.mapred.SequenceFileInputFormat,\\\"/b\\\"))\";\njob.set(\"mapred.join.expr\", expr);\ntry {\n  new CompositeInputFormat<Text>().setFormat(job); // dry-run parse client-side\n} catch (IOException e) {\n  throw new IllegalArgumentException(\"bad join expr: \" + expr, e);\n}","typeGuard":"boolean isNodeToken(Parser.Token t) {\n  return Parser.TType.CIF.equals(t.getType()); // only NodeToken carries a Node\n}","tryCatchPattern":"try {\n  new CompositeInputFormat<Object>().setFormat(job);\n} catch (IOException e) {\n  throw new IllegalArgumentException(\n      \"mapred.join.expr must contain only function-call arguments like tbl(...)\", e);\n}","preventionTips":["Never hand-type the expression; use CompositeInputFormat.compose(op, fmt, paths...)","Every argument of inner/outer/override must be a function call, not a bare name or string","Dry-run setFormat(job) in a unit test for every expression your job config ships"],"tags":["hadoop","mapreduce","join","parser","expression","dsl"],"backgroundTag":"expression-parse-error","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}