{"record":{"id":"955df0d67b1115d9","repo":"apache/hadoop","slug":"named-output-not-defined","errorCode":null,"errorMessage":"Named output '{}' not defined","messagePattern":"Named output '(.+?)' not defined","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/mapred/lib/MultipleOutputs.java","lineNumber":179,"sourceCode":"  /**\n   * Checks if a named output is alreadyDefined or not.\n   *\n   * @param conf           job conf\n   * @param namedOutput    named output names\n   * @param alreadyDefined whether the existence/non-existence of\n   *                       the named output is to be checked\n   * @throws IllegalArgumentException if the output name is alreadyDefined or\n   *                                  not depending on the value of the\n   *                                  'alreadyDefined' parameter\n   */\n  private static void checkNamedOutput(JobConf conf, String namedOutput,\n                                       boolean alreadyDefined) {\n    List<String> definedChannels = getNamedOutputsList(conf);\n    if (alreadyDefined && definedChannels.contains(namedOutput)) {\n      throw new IllegalArgumentException(\"Named output '\" + namedOutput +\n        \"' already alreadyDefined\");\n    } else if (!alreadyDefined && !definedChannels.contains(namedOutput)) {\n      throw new IllegalArgumentException(\"Named output '\" + namedOutput +\n        \"' not defined\");\n    }\n  }\n\n  /**\n   * Checks if a named output name is valid token.\n   *\n   * @param namedOutput named output Name\n   * @throws IllegalArgumentException if the output name is not valid.\n   */\n  private static void checkTokenName(String namedOutput) {\n    if (namedOutput == null || namedOutput.length() == 0) {\n      throw new IllegalArgumentException(\n        \"Name cannot be NULL or emtpy\");\n    }\n    for (char ch : namedOutput.toCharArray()) {\n      if ((ch >= 'A') && (ch <= 'Z')) {\n        continue;","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/lib/MultipleOutputs.java#L161-L197","documentation":"MultipleOutputs throws this IllegalArgumentException from checkNamedOutput(conf, name, false) when a configuration-level lookup references a named output that was never registered via addNamedOutput/addMultiNamedOutput. The check backs the static getters isMultiNamedOutput(conf, name), getNamedOutputFormatClass(conf, name), getNamedOutputKeyClass and getNamedOutputValueClass — each of them first verifies the name exists in 'mo.namedOutputs'. It fires during job setup or at task time, not while writing records.","triggerScenarios":"Calling MultipleOutputs.getNamedOutputFormatClass(conf, \"channelX\", ...) or isMultiNamedOutput(conf, \"channelX\") for a name that has no addNamedOutput(conf, \"channelX\", ...) call anywhere. Also reached indirectly: the task-side InternalFileOutputFormat.getRecordWriter resolves the configured named output's format class, so a JobConf that carries mo.config.namedOutput but lost the mo.namedOutputs/mo.namedOutput.* entries fails here.","commonSituations":"Driver and task code drifting out of sync after a rename of a named output; JobConf built in one place and stripped/serialized in another (XML round-trip dropping keys); typos between registration and lookup strings.","solutions":["Register the name before any lookup: MultipleOutputs.addNamedOutput(conf, \"channelX\", formatClass, keyClass, valueClass)","Define the name once as a constant and use it in both addNamedOutput and all get* calls","Dump conf.get(\"mo.namedOutputs\") to confirm which channels are actually registered before lookup"],"exampleFix":"// before: lookup without registration -> IllegalArgumentException\nMultipleOutputs.getNamedOutputFormatClass(conf, \"summary\");\n\n// after: register first, then query\nMultipleOutputs.addNamedOutput(conf, \"summary\", TextOutputFormat.class, Text.class, Text.class);\nClass<? extends OutputFormat> fmt = MultipleOutputs.getNamedOutputFormatClass(conf, \"summary\");","handlingStrategy":"validation","validationCode":"// verify registration before any static lookup\nif (!MultipleOutputs.getNamedOutputsList(conf).contains(name)) {\n  throw new IllegalArgumentException(\"named output not registered: \" + name);\n}\nClass<? extends OutputFormat> f = MultipleOutputs.getNamedOutputFormatClass(conf, name);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use shared constants for channel names in driver and lookups","After building the JobConf, assert getNamedOutputsList(conf) equals the expected set","Treat 'not defined' as a wiring bug caught at setup time, not as a retryable failure"],"tags":["hadoop","mapreduce","multiple-outputs","configuration","registration"],"backgroundTag":"unregistered-name-lookup","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}