apache/hadoop · error · IOException

No RecordReader for {}

Error message

No RecordReader for {}

What it means

Parser.WNode.createRecordReader (Parser.java:343) looks up a ComposableRecordReader constructor in the rrCstrMap registry keyed by the node identifier. For wrapped nodes only 'tbl' is registered by default (CompositeInputFormat.addDefaults). The error means the identifier parsed for this wrapped node has a Node type registered but no matching ComposableRecordReader entry.

Source

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

    private Configuration getConf(Configuration jconf) throws IOException {
      Job job = Job.getInstance(jconf);
      FileInputFormat.setInputPaths(job, indir);
      return job.getConfiguration();
    }
    
    public List<InputSplit> getSplits(JobContext context)
        throws IOException, InterruptedException {
      return inf.getSplits(
                 new JobContextImpl(getConf(context.getConfiguration()), 
                                    context.getJobID()));
    }

    public ComposableRecordReader<?, ?> createRecordReader(InputSplit split, 
        TaskAttemptContext taskContext) 
        throws IOException, InterruptedException {
      try {
        if (!rrCstrMap.containsKey(ident)) {
          throw new IOException("No RecordReader for " + ident);
        }
        Configuration conf = getConf(taskContext.getConfiguration());
        TaskAttemptContext context = 
          new TaskAttemptContextImpl(conf, 
              TaskAttemptID.forName(conf.get(MRJobConfig.TASK_ATTEMPT_ID)), 
              new WrappedStatusReporter(taskContext));
        return rrCstrMap.get(ident).newInstance(id,
            inf.createRecordReader(split, context), cmpcl);
      } catch (IllegalAccessException e) {
        throw new IOException(e);
      } catch (InstantiationException e) {
        throw new IOException(e);
      } catch (InvocationTargetException e) {
        throw new IOException(e);
      }
    }

    public String toString() {

View on GitHub (pinned to 2add963021)

Solutions

  1. Use only the default 'tbl' identifier for wrapped inputs, e.g. tbl(fmt, "path")
  2. For custom wrapped node types, register both maps: Parser.WNode.addIdentifier("myident", MyWrappedRecordReader.class) via mapreduce.join.define.<ident> style extension or subclass CompositeInputFormat.addDefaults
  3. Verify the exact identifier spelling in the expression against what addIdentifier registered
  4. Ensure job client and cluster run the same Hadoop mapreduce-client-core version so identifier registries match

Example fix

// before
protected void addDefaults() {
  super.addDefaults();
  // custom node parsed, but no record reader registered for "myfile"
  try { Parser.Node.addIdentifier("myfile", new Class[]{Integer.TYPE, RecordReader.class, Class.class}, MyNode.class, null); }
  catch (NoSuchMethodException e) { }
}

// after
protected void addDefaults() {
  super.addDefaults();
  try { Parser.WNode.addIdentifier("myfile", MyWrappedRecordReader.class); }
  catch (NoSuchMethodException e) { throw new RuntimeException(e); }
}
Defensive patterns

Strategy: validation

Validate before calling

static void requireRegisteredWrappedIdent(String ident) {
  if (!"tbl".equals(ident)) {
    throw new IllegalArgumentException(
      "Wrapped input ident '" + ident + "' has no default ComposableRecordReader; register via Parser.WNode.addIdentifier");
  }
}

Try / catch

try { cif.createRecordReader(split, ctx); } catch (IOException e) { if (e.getMessage().startsWith("No RecordReader")) { /* re-register identifier, resubmit task */ } throw e; }

Prevention

When it happens

Trigger: A join expression uses a wrapped-position identifier other than 'tbl' (e.g. 'file(...)' or a custom ident) that was registered in nodeCstrMap but never got a rrCstrMap entry via addIdentifier; or custom parser extension registers a Node subclass directly without a record-reader class; classpath skew where a stale Parser subclass registered different identifiers on the client vs the task JVM.

Common situations: Extending the join framework with custom node types without calling Parser.WNode.addIdentifier/CNode.addIdentifier; using inner/outer/override in a tbl position or a misspelled 'tbl' ('Tbl', 'table') so it resolves to a differently-registered ident; running with mismatched Hadoop versions between job client and cluster.

Related errors


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