{"record":{"id":"ef264a0883134bb9","repo":"apache/hadoop","slug":"name-output-has-not-been-defined-as-multi","errorCode":null,"errorMessage":"Name output '{}' has not been defined as multi","messagePattern":"Name output '(.+?)' has not been defined as multi","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":529,"sourceCode":"   * @param multiName   the multi name part\n   * @param reporter    the reporter\n   * @return the output collector for the given named output\n   * @throws IOException thrown if output collector could not be created\n   */\n  @SuppressWarnings({\"unchecked\"})\n  public OutputCollector getCollector(String namedOutput, String multiName,\n                                      Reporter reporter)\n    throws IOException {\n\n    checkNamedOutputName(namedOutput);\n    if (!namedOutputs.contains(namedOutput)) {\n      throw new IllegalArgumentException(\"Undefined named output '\" +\n        namedOutput + \"'\");\n    }\n    boolean multi = isMultiNamedOutput(conf, namedOutput);\n\n    if (!multi && multiName != null) {\n      throw new IllegalArgumentException(\"Name output '\" + namedOutput +\n        \"' has not been defined as multi\");\n    }\n    if (multi) {\n      checkTokenName(multiName);\n    }\n\n    String baseFileName = (multi) ? namedOutput + \"_\" + multiName : namedOutput;\n\n    final RecordWriter writer =\n      getRecordWriter(namedOutput, baseFileName, reporter);\n\n    return new OutputCollector() {\n\n      @SuppressWarnings({\"unchecked\"})\n      public void collect(Object key, Object value) throws IOException {\n        writer.write(key, value);\n      }\n","sourceCodeStart":511,"sourceCodeEnd":547,"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#L511-L547","documentation":"A named output in MultipleOutputs is either single (one file per task, registered with addNamedOutput) or multi (an unbounded set of files named name_multiName, registered with addMultiNamedOutput, which sets mo.namedOutput.<name>.multi=true). getCollector(name, multiName, reporter) throws this IllegalArgumentException when multiName is not null but the channel was registered as single. The framework refuses to guess which file family you meant.","triggerScenarios":"Driver registers MultipleOutputs.addNamedOutput(conf, \"seq\", ...) (single), then task code calls mos.getCollector(\"seq\", \"A\", reporter) with a second-level name. Typical when the channel was originally multi and someone 'simplified' the driver call to addNamedOutput, or when example code for multi outputs was mixed with a single-output driver.","commonSituations":"Sharding output by key/category (getCollector(\"seq\", keyCategory, reporter)) where the driver author didn't realize the multi variant needs addMultiNamedOutput; upgrading old job templates that only registered single outputs.","solutions":["Register the channel as multi: MultipleOutputs.addMultiNamedOutput(conf, \"seq\", SequenceFileOutputFormat.class, keyClass, valueClass)","If you really want a single file, call getCollector(\"seq\", reporter) without the multiName argument","Keep the single/multi decision in the same place as the registration so driver and task code cannot disagree"],"exampleFix":"// before: single registration + multi call -> IllegalArgumentException\nMultipleOutputs.addNamedOutput(conf, \"seq\", SequenceFileOutputFormat.class, LongWritable.class, Text.class);\nmos.getCollector(\"seq\", \"A\", reporter);\n\n// after: multi registration matches the multi call\nMultipleOutputs.addMultiNamedOutput(conf, \"seq\", SequenceFileOutputFormat.class, LongWritable.class, Text.class);\nmos.getCollector(\"seq\", \"A\", reporter);","handlingStrategy":"validation","validationCode":"// check the mode before deciding the call shape\nif (MultipleOutputs.isMultiNamedOutput(conf, \"seq\")) {\n  collector = mos.getCollector(\"seq\", multiName, reporter);\n} else {\n  collector = mos.getCollector(\"seq\", reporter);\n}","typeGuard":"static boolean isMulti(JobConf conf, String name) {\n  return MultipleOutputs.isMultiNamedOutput(conf, name);\n}","tryCatchPattern":null,"preventionTips":["Register with addMultiNamedOutput exactly when task code passes a multiName","Keep registration and usage side by side in one config class so they cannot diverge","Decide single vs multi once, centrally — not per call site"],"tags":["hadoop","mapreduce","multiple-outputs","multi-output","api-misuse"],"backgroundTag":"single-multi-mode-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}