apache/hadoop · error · IllegalStateException

A Mapper can be added to the chain only after the Reducer ha

Error message

A Mapper can be added to the chain only after the Reducer has been set

What it means

ChainReducer composes map-reduce-map pipelines; the reducer must be registered before any reducer-side mapper. checkReducerAlreadySet(shouldSet=true) throws IllegalStateException("A Mapper can be added to the chain only after the Reducer has been set") when ChainReducer.addMapper(...) is called while the 'chain reducer class' key is absent from the job configuration, i.e. ChainReducer.setReducer(...) has not been invoked yet.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/chain/Chain.java:655

    // set the mapper class
    int index = getIndex(jobConf, prefix);
    jobConf.setClass(prefix + CHAIN_MAPPER_CLASS + index, klass, Mapper.class);

    validateKeyValueTypes(isMap, jobConf, inputKeyClass, inputValueClass,
        outputKeyClass, outputValueClass, index, prefix);

    setMapperConf(isMap, jobConf, inputKeyClass, inputValueClass,
        outputKeyClass, outputValueClass, mapperConf, index, prefix);
  }

  // if a reducer chain check the Reducer has been already set or not
  protected static void checkReducerAlreadySet(boolean isMap,
      Configuration jobConf, String prefix, boolean shouldSet) {
    if (!isMap) {
      if (shouldSet) {
        if (jobConf.getClass(prefix + CHAIN_REDUCER_CLASS, null) == null) {
          throw new IllegalStateException(
              "A Mapper can be added to the chain only after the Reducer has "
                  + "been set");
        }
      } else {
        if (jobConf.getClass(prefix + CHAIN_REDUCER_CLASS, null) != null) {
          throw new IllegalStateException("Reducer has been already set");
        }
      }
    }
  }

  protected static void validateKeyValueTypes(boolean isMap,
      Configuration jobConf, Class<?> inputKeyClass, Class<?> inputValueClass,
      Class<?> outputKeyClass, Class<?> outputValueClass, int index,
      String prefix) {
    // if it is a reducer chain and the first Mapper is being added check the
    // key and value input classes of the mapper match those of the reducer
    // output.

View on GitHub (pinned to 2add963021)

Solutions

  1. Call ChainReducer.setReducer(job, Reducer.class, inK, inV, outK, outV, byValue) first, then every ChainReducer.addMapper(...), then submit.
  2. Centralize the wiring order in one builder method so call order cannot regress.
  3. Ensure setReducer's class/key/value arguments are non-null so registration actually stores the reducer.

Example fix

// before
ChainReducer.addMapper(job, CleanupMapper.class,
    Text.class, Text.class, Text.class, Text.class, false); // IllegalStateException
ChainReducer.setReducer(job, Reduce.class,
    LongWritable.class, Text.class, Text.class, Text.class, false);

// after
ChainReducer.setReducer(job, Reduce.class,
    LongWritable.class, Text.class, Text.class, Text.class, false);
ChainReducer.addMapper(job, CleanupMapper.class,
    Text.class, Text.class, Text.class, Text.class, false);
Defensive patterns

Strategy: validation

Validate before calling

// enforce ordering in one builder method
static void wireChain(Job job) {
  ChainReducer.setReducer(job, Reduce.class,
      LongWritable.class, Text.class, Text.class, IntWritable.class, false);
  ChainReducer.addMapper(job, PostMap.class,
      Text.class, IntWritable.class, Text.class, Text.class, false);
}

Prevention

When it happens

Trigger: Calling ChainReducer.addMapper(job, ...) before ChainReducer.setReducer(job, ...) on the same Job/Configuration; or setReducer arguments (e.g. reducerClass) wrong so the class key was never stored. Only applies to the reducer-side chain (!isMap); ChainMapper has no such ordering rule.

Common situations: Refactors reordering builder calls; adapting a ChainMapper example into a ChainReducer flow; copying job-assembly code that sets the mapper chain first out of habit.

Related errors


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