{"record":{"id":"3a5c5116d66a8f66","repo":"apache/hadoop","slug":"named-output-already-alreadydefined","errorCode":null,"errorMessage":"Named output '{}' already alreadyDefined","messagePattern":"Named output '(.+?)' already alreadyDefined","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":176,"sourceCode":"  private static final String COUNTERS_GROUP = MultipleOutputs.class.getName();\n  private static final Logger LOG = LoggerFactory.getLogger(MultipleOutputs.class);\n\n  /**\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    }","sourceCodeStart":158,"sourceCodeEnd":194,"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#L158-L194","documentation":"MultipleOutputs stores named outputs as entries under the 'mo.namedOutputs' configuration property. checkNamedOutput(conf, name, true) runs inside addNamedOutput/addMultiNamedOutput and throws this IllegalArgumentException (the message contains a duplicated word, 'already alreadyDefined') when the name is already present in that list. It is a guard against re-registering the same output channel twice with potentially different settings.","triggerScenarios":"Two calls to MultipleOutputs.addNamedOutput(conf, \"text\", ...) (or one addNamedOutput plus one addMultiNamedOutput) with the same name in job setup code. Also happens when driver code runs in a loop (e.g. per input path) and adds a fixed named output on every iteration against the same JobConf.","commonSituations":"Copy-pasted job setup blocks; refactoring that merges two job builders that both register the same channel; loops that add a channel once per shard instead of once per job.","solutions":["Register each named output exactly once per JobConf; move the addNamedOutput call out of loops","Before adding, check MultipleOutputs.getNamedOutputsList(conf).contains(name) and skip if present","If two channels were intended, give them distinct names (e.g. text1, text2)","Rebuild the JobConf from scratch instead of reusing one that already has mo.namedOutputs set"],"exampleFix":"// before: second registration -> IllegalArgumentException\nMultipleOutputs.addNamedOutput(conf, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\nMultipleOutputs.addNamedOutput(conf, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\n\n// after: idempotent registration\nif (!MultipleOutputs.getNamedOutputsList(conf).contains(\"text\")) {\n  MultipleOutputs.addNamedOutput(conf, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\n}","handlingStrategy":"validation","validationCode":"// make registration idempotent\nif (!MultipleOutputs.getNamedOutputsList(conf).contains(\"text\")) {\n  MultipleOutputs.addNamedOutput(conf, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register named outputs once, at a single place in the driver — never inside loops that reuse one JobConf","Wrap addNamedOutput calls in a contains() guard if setup code can run twice","Fail the driver fast on IllegalArgumentException during setup — it always indicates a setup bug"],"tags":["hadoop","mapreduce","multiple-outputs","duplicate","configuration"],"backgroundTag":"duplicate-key-registration","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}