apache/hadoop · error · IllegalArgumentException

Named output '{namedOutput}' not defined

Error message

Named output '{namedOutput}' not defined

What it means

Thrown as IllegalArgumentException from MultipleOutputs.checkNamedOutputName (MultipleOutputs.java:269) when a name is used for writing but is NOT in the mapreduce.multipleoutputs list of the Configuration visible to the running context. It is the inverse check of the duplicate guard: write() demands alreadyDefined==false channels to exist. Root cause is always a registration/config-visibility mismatch.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/output/MultipleOutputs.java:269

    }
  }
  
  /**
   * Checks if a named output name is valid.
   *
   * @param namedOutput named output Name
   * @throws IllegalArgumentException if the output name is not valid.
   */
  private static void checkNamedOutputName(JobContext job,
      String namedOutput, boolean alreadyDefined) {
    checkTokenName(namedOutput);
    checkBaseOutputPath(namedOutput);
    List<String> definedChannels = getNamedOutputsList(job);
    if (alreadyDefined && definedChannels.contains(namedOutput)) {
      throw new IllegalArgumentException("Named output '" + namedOutput +
        "' already alreadyDefined");
    } else if (!alreadyDefined && !definedChannels.contains(namedOutput)) {
      throw new IllegalArgumentException("Named output '" + namedOutput +
        "' not defined");
    }
  }

  // Returns list of channel names.
  private static List<String> getNamedOutputsList(JobContext job) {
    List<String> names = new ArrayList<String>();
    StringTokenizer st = new StringTokenizer(
      job.getConfiguration().get(MULTIPLE_OUTPUTS, ""), " ");
    while (st.hasMoreTokens()) {
      names.add(st.nextToken());
    }
    return names;
  }

  // Returns the named output OutputFormat.
  @SuppressWarnings("unchecked")
  private static Class<? extends OutputFormat<?, ?>> getNamedOutputFormatClass(

View on GitHub (pinned to 2add963021)

Solutions

  1. Align the names: define channel names as public static final String constants used by both the driver's addNamedOutput and the task's mos.write
  2. Ensure addNamedOutput runs on the Job's Configuration BEFORE job.submit()/waitForCompletion()
  3. Verify the key arrives in tasks: dump conf.get("mapreduce.multipleoutputs") in the Mapper's setup() and compare with the driver

Example fix

// driver
public static final String CH_TEXT = "text";
MultipleOutputs.addNamedOutput(job, CH_TEXT, TextOutputFormat.class, LongWritable.class, Text.class);

// reducer -- before: mos.write("txt", k, v);  // typo -> 'not defined'
// reducer -- after:
mos.write(Driver.CH_TEXT, k, v);
Defensive patterns

Strategy: validation

Validate before calling

// driver-side assertion before submit
List<String> registered = Arrays.asList(
    conf.get("mapreduce.multipleoutputs", "").split(" "));
for (String used : CHANNELS_USED_IN_TASKS) {
  if (!registered.contains(used)) throw new IllegalStateException("Unregistered channel: " + used);
}

Prevention

When it happens

Trigger: mos.write("txt", k, v) in a Mapper/Reducer while the job only registered 'text' (typo/case mismatch); addNamedOutput called on a DIFFERENT Job/Configuration than the one the task sees (e.g. registered after job submission, on a copy, or on the client's conf while tasks deserialize a conf snapshot taken earlier); conf whitelisting stripped mapreduce.multipleoutputs.namedOutput.* keys.

Common situations: Name typos between driver and reducer code; calling addNamedOutput after job.submit(); frameworks (Tez, Spark-Hadoop bridges, custom runners) that filter which conf keys reach the task; case-sensitive 'Text' vs 'text'.

Related errors


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