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

  1. Call setFormat(job) — or run through CompositeInputFormat.getRecordReader — so identifiers are registered first
  2. Register custom operators with mapred.join.define.<ident> pointing at a ComposableRecordReader exposing the (int, JobConf, int, Class) constructor
  3. 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

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.