apache/hadoop · error · IOException
No RecordReader for {}
Error message
No RecordReader for {} What it means
CNode.getRecordReader resolves the composite operator (inner/outer/override or a mapred.join.define identifier) to a ComposableRecordReader constructor via rrCstrMap, throwing IOException("No RecordReader for <ident>") when the identifier is absent. As with the wrapped-node variant, the stock flow registers these in CompositeInputFormat.setFormat before readers are created, so this indicates the node tree was driven without registration, or an extension split the node/reader registration, or classloader duplication diverged the static maps.
Source
Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:413
ret[i].add(splits[j][i]);
}
}
return ret;
}
@SuppressWarnings("unchecked") // child types unknowable
public ComposableRecordReader getRecordReader(
InputSplit split, JobConf job, Reporter reporter) throws IOException {
if (!(split instanceof CompositeInputSplit)) {
throw new IOException("Invalid split type:" +
split.getClass().getName());
}
final CompositeInputSplit spl = (CompositeInputSplit)split;
final int capacity = kids.size();
CompositeRecordReader ret = null;
try {
if (!rrCstrMap.containsKey(ident)) {
throw new IOException("No RecordReader for " + ident);
}
ret = (CompositeRecordReader)
rrCstrMap.get(ident).newInstance(id, job, capacity, cmpcl);
} 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);
}
for (int i = 0; i < capacity; ++i) {
ret.add(kids.get(i).getRecordReader(spl.get(i), job, reporter));
}
return (ComposableRecordReader)ret;
}
/**
* Parse a list of comma-separated nodes.View on GitHub (pinned to 2add963021)
Solutions
- Call setFormat(job) — or run through CompositeInputFormat.getRecordReader — so identifiers are registered first
- Register custom operators with mapred.join.define.<ident> pointing at a ComposableRecordReader exposing the (int, JobConf, int, Class) constructor
- Ensure a single classloader loads the join package
Example fix
// before Parser.Node root = /* CNode obtained directly */; root.getRecordReader(split, job, reporter); // No RecordReader for inner // after CompositeInputFormat<?> cif = new CompositeInputFormat<Object>(); cif.setFormat(job); // registers inner/outer/override/tbl ComposableRecordReader<?, ?> rr = cif.getRecordReader(split, job, reporter);
Defensive patterns
Strategy: validation
Validate before calling
// initialize identifiers before any reader construction
CompositeInputFormat<Text> cif = new CompositeInputFormat<Text>();
cif.setFormat(job); // addDefaults() + mapred.join.define.* registered here
ComposableRecordReader<Text, TupleWritable> rr =
cif.getRecordReader(split, job, reporter); Try / catch
try {
return root.getRecordReader(split, job, reporter);
} catch (IOException e) {
throw new IOException("composite operator not registered; run through "
+ "CompositeInputFormat.setFormat or add mapred.join.define.<ident>", e);
} Prevention
- Always route reader construction through CompositeInputFormat.getRecordReader
- Give custom operators a (int, JobConf, int, Class) constructor and register them via mapred.join.define
- Prevent multi-classloader loading of the join package
When it happens
Trigger: Custom code obtaining a Parser.CNode and calling getRecordReader without CompositeInputFormat.setFormat; an extension registering only the node constructor for an identifier; the join package loaded by two classloaders so the static rrCstrMap seen by the reader differs from the one used at parse time.
Common situations: Framework extensions and unit tests that hand-drive the parser; custom operators defined via mapred.join.define in one conf but executed with another; application-server style classloader isolation.
Related errors
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/6f18b900d4606ce4.
Report an issue: GitHub.