{"record":{"id":"15f973b385fabf05","repo":"apache/hadoop","slug":"undefined-named-output-namedoutput","errorCode":null,"errorMessage":"Undefined named output '{namedOutput}'","messagePattern":"Undefined named output '(.+?)'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/output/MultipleOutputs.java","lineNumber":450,"sourceCode":"   * Write key and value to baseOutputPath using the namedOutput.\n   * \n   * @param namedOutput    the named output name\n   * @param key            the key\n   * @param value          the value\n   * @param baseOutputPath base-output path to write the record to.\n   * Note: Framework will generate unique filename for the baseOutputPath\n   * <b>Warning</b>: when the baseOutputPath is a path that resolves\n   * outside of the final job output directory, the directory is created\n   * immediately and then persists through subsequent task retries, breaking\n   * the concept of output committing.\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <K, V> void write(String namedOutput, K key, V value,\n      String baseOutputPath) throws IOException, InterruptedException {\n    checkNamedOutputName(context, namedOutput, false);\n    checkBaseOutputPath(baseOutputPath);\n    if (!namedOutputs.contains(namedOutput)) {\n      throw new IllegalArgumentException(\"Undefined named output '\" +\n        namedOutput + \"'\");\n    }\n    TaskAttemptContext taskContext = getContext(namedOutput);\n    getRecordWriter(taskContext, baseOutputPath).write(key, value);\n  }\n\n  /**\n   * Write key value to an output file name.\n   * \n   * Gets the record writer from job's output format.  \n   * Job's output format should be a FileOutputFormat.\n   * \n   * @param key       the key\n   * @param value     the value\n   * @param baseOutputPath base-output path to write the record to.\n   * Note: Framework will generate unique filename for the baseOutputPath\n   * <b>Warning</b>: when the baseOutputPath is a path that resolves\n   * outside of the final job output directory, the directory is created","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/output/MultipleOutputs.java#L432-L468","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do all addNamedOutput calls at job-setup time, before any MultipleOutputs instance is constructed in setup()","Construct MultipleOutputs fresh (in Mapper/Reducer setup) after all registration is complete; never add channels mid-task","In tests, build the Job conf fully first, then new MultipleOutputs(new TaskAttemptContextImpl(conf, attemptId))"],"exampleFix":"// before (test / shared-conf scenario)\nMultipleOutputs<Text, Text> mos = new MultipleOutputs<>(context);\nMultipleOutputs.addNamedOutput(job, \"late\", TextOutputFormat.class, ...); // after snapshot\nmos.write(\"late\", k, v); // config has it, instance set does not -> throws\n\n// after\nMultipleOutputs.addNamedOutput(job, \"late\", TextOutputFormat.class, ...);\nMultipleOutputs<Text, Text> mos = new MultipleOutputs<>(context); // snapshot includes 'late'\nmos.write(\"late\", k, v);","handlingStrategy":"validation","validationCode":"// construct MOS only after registration is complete\n// driver: all addNamedOutput(...) calls first, then submit\n// task setup:\nprotected void setup(Context context) {\n  mos = new MultipleOutputs<>(context); // snapshot now includes every channel\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call addNamedOutput after creating a MultipleOutputs instance","In tests, finalize the Job conf before building the MOS","Treat task conf as immutable at runtime"],"tags":["hadoop","mapreduce","multiple-outputs","undefined-channel","ordering","illegalargument"],"backgroundTag":"undefined-named-output","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}