apache/hadoop · error · IOException

No nodetype for " + ident

Error message

No nodetype for " + ident

What it means

Node.forIdent maps the function name in the expression to a parse-tree node class. Built-ins are inner, outer, and override (composite nodes) plus tbl (wrapped node), registered by CompositeInputFormat.addDefaults(); anything else must be declared via the mapred.join.define.<ident> job property pointing at a ComposableRecordReader. forIdent throws IOException("No nodetype for <ident>") when the name is in neither mapping.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:196

      }
    }
  }

  @InterfaceAudience.Public
  @InterfaceStability.Evolving
  public abstract static class Node implements ComposableInputFormat {
    /**
     * Return the node type registered for the particular identifier.
     * By default, this is a CNode for any composite node and a WNode
     * for &quot;wrapped&quot; nodes. User nodes will likely be composite
     * nodes.
     * @see #addIdentifier(java.lang.String, java.lang.Class[], java.lang.Class, java.lang.Class)
     * @see CompositeInputFormat#setFormat(org.apache.hadoop.mapred.JobConf)
     */
    static Node forIdent(String ident) throws IOException {
      try {
        if (!nodeCstrMap.containsKey(ident)) {
          throw new IOException("No nodetype for " + ident);
        }
        return nodeCstrMap.get(ident).newInstance(ident);
      } catch (IllegalAccessException e) {
        throw (IOException)new IOException().initCause(e);
      } catch (InstantiationException e) {
        throw (IOException)new IOException().initCause(e);
      } catch (InvocationTargetException e) {
        throw (IOException)new IOException().initCause(e);
      }
    }

    private static final Class<?>[] ncstrSig = { String.class };
    private static final
        Map<String,Constructor<? extends Node>> nodeCstrMap =
        new HashMap<String,Constructor<? extends Node>>();
    protected static final
        Map<String,Constructor<? extends ComposableRecordReader>> rrCstrMap =
        new HashMap<String,Constructor<? extends ComposableRecordReader>>();

View on GitHub (pinned to 2add963021)

Solutions

  1. Use one of inner, outer, override, tbl exactly, in lowercase
  2. For custom types, set mapred.join.define.<ident> to the ComposableRecordReader class in the same job conf that runs the join
  3. Dry-run new CompositeInputFormat().setFormat(job) client-side to catch unknown identifiers before submission

Example fix

// before
job.set("mapred.join.expr", "JOIN(tbl(F,/a),tbl(F,/b))");

// after
job.set("mapred.join.expr",
    CompositeInputFormat.compose("outer", SequenceFileInputFormat.class, "/a", "/b"));
Defensive patterns

Strategy: validation

Validate before calling

String op = "outer"; // or inner, override, tbl, or a defined ident
if (!Arrays.asList("inner", "outer", "override", "tbl").contains(op)
    && job.get("mapred.join.define." + op) == null) {
  throw new IllegalArgumentException("unknown join operator: " + op);
}
job.set("mapred.join.expr", CompositeInputFormat.compose(op, fmt, paths));

Try / catch

try {
  new CompositeInputFormat<Object>().setFormat(job);
} catch (IOException e) {
  throw new IllegalArgumentException(
      "unknown operator in mapred.join.expr; use inner/outer/override/tbl "
      + "or set mapred.join.define.<ident>", e);
}

Prevention

When it happens

Trigger: Typos or wrong case in the operator name: Inner(...), join(...), JOIN(...); using a custom operator without setting mapred.join.define.<name>; setting the define property on a different JobConf than the one passed to setFormat.

Common situations: Hand-written expressions; carrying a custom join type from one job into another without its mapred.join.define.* property; assuming operator names are case-insensitive.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/e56bb376205e26b3. Report an issue: GitHub.