apache/hadoop · error · IllegalArgumentException

Undefined named output '{namedOutput}'

Error message

Undefined named output '{namedOutput}'

What it means

Thrown as IllegalArgumentException from MultipleOutputs.write (MultipleOutputs.java:450). Unlike the sibling 'not defined' check (which reads the Configuration live), this guard checks the instance-level set namedOutputs, snapshotted once in the MultipleOutputs constructor from the context configuration. It fires when the name passes the config check but is missing from that snapshot — i.e. the Configuration was mutated to add the named output AFTER the MultipleOutputs instance was created.

Source

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

   * Write key and value to baseOutputPath using the namedOutput.
   * 
   * @param namedOutput    the named output name
   * @param key            the key
   * @param value          the value
   * @param baseOutputPath base-output path to write the record to.
   * Note: Framework will generate unique filename for the baseOutputPath
   * <b>Warning</b>: when the baseOutputPath is a path that resolves
   * outside of the final job output directory, the directory is created
   * immediately and then persists through subsequent task retries, breaking
   * the concept of output committing.
   */
  @SuppressWarnings("unchecked")
  public <K, V> void write(String namedOutput, K key, V value,
      String baseOutputPath) throws IOException, InterruptedException {
    checkNamedOutputName(context, namedOutput, false);
    checkBaseOutputPath(baseOutputPath);
    if (!namedOutputs.contains(namedOutput)) {
      throw new IllegalArgumentException("Undefined named output '" +
        namedOutput + "'");
    }
    TaskAttemptContext taskContext = getContext(namedOutput);
    getRecordWriter(taskContext, baseOutputPath).write(key, value);
  }

  /**
   * Write key value to an output file name.
   * 
   * Gets the record writer from job's output format.  
   * Job's output format should be a FileOutputFormat.
   * 
   * @param key       the key
   * @param value     the value
   * @param baseOutputPath base-output path to write the record to.
   * Note: Framework will generate unique filename for the baseOutputPath
   * <b>Warning</b>: when the baseOutputPath is a path that resolves
   * outside of the final job output directory, the directory is created

View on GitHub (pinned to 2add963021)

Solutions

  1. Do all addNamedOutput calls at job-setup time, before any MultipleOutputs instance is constructed in setup()
  2. Construct MultipleOutputs fresh (in Mapper/Reducer setup) after all registration is complete; never add channels mid-task
  3. In tests, build the Job conf fully first, then new MultipleOutputs(new TaskAttemptContextImpl(conf, attemptId))

Example fix

// before (test / shared-conf scenario)
MultipleOutputs<Text, Text> mos = new MultipleOutputs<>(context);
MultipleOutputs.addNamedOutput(job, "late", TextOutputFormat.class, ...); // after snapshot
mos.write("late", k, v); // config has it, instance set does not -> throws

// after
MultipleOutputs.addNamedOutput(job, "late", TextOutputFormat.class, ...);
MultipleOutputs<Text, Text> mos = new MultipleOutputs<>(context); // snapshot includes 'late'
mos.write("late", k, v);
Defensive patterns

Strategy: validation

Validate before calling

// construct MOS only after registration is complete
// driver: all addNamedOutput(...) calls first, then submit
// task setup:
protected void setup(Context context) {
  mos = new MultipleOutputs<>(context); // snapshot now includes every channel
}

Prevention

When it happens

Trigger: In task code (usually unit tests or embedded/local runners that share one Configuration object): construct new MultipleOutputs(context), then call addNamedOutput(jobUsingSameConf, name, ...) (or otherwise set mapreduce.multipleoutputs), then mos.write(name, ...) — the config now contains the channel, but the instance set does not. In normal cluster runs the task conf is immutable, so the earlier 'not defined' error (4337) is what you hit instead.

Common situations: Unit tests driving MultipleOutputs directly with a shared Configuration; helper libraries that lazily register channels during reduce(); MRLocalJobRunner-based tests where driver and task share conf state in one JVM.

Related errors


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