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 "wrapped" 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
- Use one of inner, outer, override, tbl exactly, in lowercase
- For custom types, set mapred.join.define.<ident> to the ComposableRecordReader class in the same job conf that runs the join
- 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
- Use the built-in operator names verbatim, all lowercase
- Ship the mapred.join.define.<ident> property with every job that uses a custom operator
- Dry-run setFormat(job) in a config unit test
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.