{"record":{"id":"a76f143db415d193","repo":"apache/hadoop","slug":"named-output-namedoutput-already-alreadydefine","errorCode":null,"errorMessage":"Named output '{namedOutput}' 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/mapreduce/lib/output/MultipleOutputs.java","lineNumber":266,"sourceCode":"  private static void checkBaseOutputPath(String outputPath) {\n    if (outputPath.equals(FileOutputFormat.PART)) {\n      throw new IllegalArgumentException(\"output name cannot be 'part'\");\n    }\n  }\n  \n  /**\n   * Checks if a named output name is valid.\n   *\n   * @param namedOutput named output Name\n   * @throws IllegalArgumentException if the output name is not valid.\n   */\n  private static void checkNamedOutputName(JobContext job,\n      String namedOutput, boolean alreadyDefined) {\n    checkTokenName(namedOutput);\n    checkBaseOutputPath(namedOutput);\n    List<String> definedChannels = getNamedOutputsList(job);\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  // Returns list of channel names.\n  private static List<String> getNamedOutputsList(JobContext job) {\n    List<String> names = new ArrayList<String>();\n    StringTokenizer st = new StringTokenizer(\n      job.getConfiguration().get(MULTIPLE_OUTPUTS, \"\"), \" \");\n    while (st.hasMoreTokens()) {\n      names.add(st.nextToken());\n    }\n    return names;\n  }\n","sourceCodeStart":248,"sourceCodeEnd":284,"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#L248-L284","documentation":"Thrown as IllegalArgumentException from MultipleOutputs.checkNamedOutputName (MultipleOutputs.java:266, message contains the upstream typo 'already alreadyDefined') when addNamedOutput is called with a name already present in the space-separated mapreduce.multipleoutputs config list. Each channel must be registered exactly once; the check exists because a second conf.set would corrupt the format/key/value properties of the channel.","triggerScenarios":"Calling MultipleOutputs.addNamedOutput(job, \"text\", ...) twice on the same Job/Configuration — e.g. a driver loop that re-adds channels on retry, shared Configuration objects in unit tests, or two components each registering the same well-known channel name.","commonSituations":"Test harnesses reusing one Configuration across test methods; job drivers that configure named outputs both statically and from parsed arguments; teams merging two jobs whose channel names clash.","solutions":["Register each named output exactly once per Job; move addNamedOutput calls into a single setup method","Before adding, read conf.get(\"mapreduce.multipleoutputs\", \"\") and skip names already present","Use distinct channel names per component (prefix by domain: 'etlText', 'auditText')"],"exampleFix":"// before: retried driver code registers twice\nMultipleOutputs.addNamedOutput(job, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\nMultipleOutputs.addNamedOutput(job, \"text\", TextOutputFormat.class, LongWritable.class, Text.class); // throws\n\n// after: idempotent registration\nString registered = job.getConfiguration().get(\"mapreduce.multipleoutputs\", \"\");\nif (!Arrays.asList(registered.split(\" \")).contains(\"text\")) {\n  MultipleOutputs.addNamedOutput(job, \"text\", TextOutputFormat.class, LongWritable.class, Text.class);\n}","handlingStrategy":"validation","validationCode":"// idempotent registration helper\nstatic void addNamedOutputOnce(Job job, String name,\n    Class<? extends OutputFormat> fmt, Class<?> k, Class<?> v) {\n  String list = job.getConfiguration().get(\"mapreduce.multipleoutputs\", \"\");\n  if (!Arrays.asList(list.split(\" \")).contains(name)) {\n    MultipleOutputs.addNamedOutput(job, name, fmt, k, v);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register channels once in a single setup method","Prefix channel names per component to avoid clashes","Do not share Configuration objects across test cases without reset"],"tags":["hadoop","mapreduce","multiple-outputs","duplicate","configuration","illegalargument"],"backgroundTag":"duplicate-named-output","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}