{"record":{"id":"08af713843b718c4","repo":"apache/hadoop","slug":"undefined-named-output","errorCode":null,"errorMessage":"Undefined named output '{}'","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/mapred/lib/MultipleOutputs.java","lineNumber":523,"sourceCode":"  }\n\n  /**\n   * Gets the output collector for a multi named output.\n   *\n   * @param namedOutput the named output name\n   * @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() {","sourceCodeStart":505,"sourceCodeEnd":541,"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#L505-L541","documentation":"The runtime (instance) MultipleOutputs object builds a set of registered channel names from 'mo.namedOutputs' in its constructor. getCollector() validates the requested name against that set and throws this IllegalArgumentException — 'Undefined named output' — when the name is a syntactically valid token (checkNamedOutputName passed) but was never registered with addNamedOutput/addMultiNamedOutput. It fires inside map/reduce code, at the moment the collector is requested.","triggerScenarios":"mos.getCollector(\"channelX\", reporter) in a Mapper/Reducer where the driver never called MultipleOutputs.addNamedOutput(conf, \"channelX\", ...). Common trigger is name drift: driver registers 'clicks' while task code asks for 'click', or the named output was registered on a different JobConf than the one the task actually received.","commonSituations":"Renaming a channel in the driver but not in the mapper/reducer (or vice versa); copy-pasting task code between jobs whose drivers register different channels; unit tests that construct MultipleOutputs with a bare JobConf lacking the mo.namedOutputs entries.","solutions":["Register the name in the job driver: MultipleOutputs.addNamedOutput(conf, \"channelX\", formatClass, keyClass, valueClass)","Use one shared constant for each channel name across driver and task code","In tests, seed the JobConf with the same addNamedOutput calls the driver would make","Debug by printing MultipleOutputs.getNamedOutputsList(conf) (or iterating mos.getNamedOutputs()) to see what the task actually knows"],"exampleFix":"// before: driver forgot the registration; reduce() throws\nmos.getCollector(\"alerts\", reporter).collect(key, value);\n\n// after: driver registers the channel once\nMultipleOutputs.addNamedOutput(conf, \"alerts\", TextOutputFormat.class, Text.class, Text.class);\n// ...and task code uses the same constant\nmos.getCollector(ALERTS_OUTPUT, reporter).collect(key, value);","handlingStrategy":"validation","validationCode":"// verify against the exact conf the task will see\nif (!MultipleOutputs.getNamedOutputsList(jobConf).contains(CHANNEL)) {\n  throw new IllegalStateException(CHANNEL + \" not registered; call MultipleOutputs.addNamedOutput first\");\n}\nOutputCollector c = mos.getCollector(CHANNEL, reporter);","typeGuard":"static boolean isRegisteredChannel(JobConf conf, String name) {\n  return MultipleOutputs.getNamedOutputsList(conf).contains(name);\n}","tryCatchPattern":"try {\n  mos.getCollector(CHANNEL, reporter).collect(key, value);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"Undefined named output\")) {\n    throw new IllegalStateException(\"channel wiring bug: \" + CHANNEL + \" missing from mo.namedOutputs\", e);\n  }\n  throw e;\n}","preventionTips":["Declare channel names as compile-time constants used by both driver and task code","In tests, build the JobConf with the same addNamedOutput calls as production","Fail fast: an undefined channel is a wiring bug, never something to catch-and-continue"],"tags":["hadoop","mapreduce","multiple-outputs","registration","runtime"],"backgroundTag":"unregistered-name-lookup","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}