{"record":{"id":"ef7ede9c0613115a","repo":"apache/hadoop","slug":"no-application-program-defined","errorCode":null,"errorMessage":"No application program defined.","messagePattern":"No application program 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/pipes/Submitter.java","lineNumber":314,"sourceCode":"      }\n    }\n    String textClassname = Text.class.getName();\n    setIfUnset(conf, MRJobConfig.MAP_OUTPUT_KEY_CLASS, textClassname);\n    setIfUnset(conf, MRJobConfig.MAP_OUTPUT_VALUE_CLASS, textClassname);\n    setIfUnset(conf, MRJobConfig.OUTPUT_KEY_CLASS, textClassname);\n    setIfUnset(conf, MRJobConfig.OUTPUT_VALUE_CLASS, textClassname);\n    \n    // Use PipesNonJavaInputFormat if necessary to handle progress reporting\n    // from C++ RecordReaders ...\n    if (!getIsJavaRecordReader(conf) && !getIsJavaMapper(conf)) {\n      conf.setClass(Submitter.INPUT_FORMAT, \n                    conf.getInputFormat().getClass(), InputFormat.class);\n      conf.setInputFormat(PipesNonJavaInputFormat.class);\n    }\n    \n    String exec = getExecutable(conf);\n    if (exec == null) {\n      throw new IllegalArgumentException(\"No application program defined.\");\n    }\n    // add default debug script only when executable is expressed as\n    // <path>#<executable>\n    if (exec.contains(\"#\")) {\n      // set default gdb commands for map and reduce task \n      String defScript = \"$HADOOP_HOME/src/c++/pipes/debug/pipes-default-script\";\n      setIfUnset(conf, MRJobConfig.MAP_DEBUG_SCRIPT,defScript);\n      setIfUnset(conf, MRJobConfig.REDUCE_DEBUG_SCRIPT,defScript);\n    }\n    URI[] fileCache = JobContextImpl.getCacheFiles(conf);\n    if (fileCache == null) {\n      fileCache = new URI[1];\n    } else {\n      URI[] tmp = new URI[fileCache.length+1];\n      System.arraycopy(fileCache, 0, tmp, 1, fileCache.length);\n      fileCache = tmp;\n    }\n    try {","sourceCodeStart":296,"sourceCodeEnd":332,"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/pipes/Submitter.java#L296-L332","documentation":"Thrown by org.apache.hadoop.mapred.pipes.Submitter while assembling a Hadoop Pipes job configuration. setJobConf reads the native C++ binary location via getExecutable(conf), which resolves the config key 'mapreduce.pipes.executable' (Submitter.EXECUTABLE). A Pipes job is only a wrapper around a native binary, so when the lookup returns null, submission aborts with IllegalArgumentException('No application program defined.') before anything is uploaded.","triggerScenarios":"Invoking the 'hadoop pipes' launcher without the -program option; calling Submitter.runJob(jobConf)/setJobConf with a JobConf that never set 'mapreduce.pipes.executable'; setting the old Hadoop 1.x key name 'hadoop.pipes.executable' instead of the current one, so getExecutable returns null at Submitter.java:312.","commonSituations":"Porting Pipes jobs from Hadoop 1.x where the property key differed; CI pipelines that build the C++ binary conditionally and skip setting the property when the build step fails; submitting a Pipes job through Oozie or a workflow engine whose job.xml omits the property.","solutions":["Pass the binary to the launcher: hadoop pipes -program /path/to/wordcount -input <in> -output <out>","Or set the property explicitly before running: jobConf.set(Submitter.EXECUTABLE, \"/path/to/wordcount\")","If the binary must ship via distributed cache, use a '<path>#<linkname>' value (the code then also installs default debug scripts when it sees '#')","Guard the call: assert Submitter.getExecutable(conf) != null before runJob to fail with your own clearer message"],"exampleFix":"// before\nJobConf conf = new JobConf(MyPipe.class);\nconf.set(\"hadoop.pipes.executable\", \"/tmp/wordcount\"); // wrong key, silently ignored\nSubmitter.runJob(conf); // IllegalArgumentException: No application program defined.\n\n// after\nJobConf conf = new JobConf(MyPipe.class);\nconf.set(Submitter.EXECUTABLE, \"/tmp/wordcount#wordcount\"); // mapreduce.pipes.executable\nSubmitter.runJob(conf);","handlingStrategy":"validation","validationCode":"// before running a Pipes job\nif (Submitter.getExecutable(conf) == null) {\n  throw new IllegalStateException(\n      \"'mapreduce.pipes.executable' (Submitter.EXECUTABLE) is not set; \"\n    + \"pass -program to the hadoop pipes command or set the property\");\n}\nSubmitter.runJob(conf);","typeGuard":null,"tryCatchPattern":"try {\n  Submitter.runJob(conf);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"No application program\")) {\n    // report missing -program / mapreduce.pipes.executable distinctly\n    throw new IllegalStateException(\"Pipes executable missing\", e);\n  }\n  throw e;\n}","preventionTips":["Make the build fail if the C++ binary is missing so CI never submits without it","Centralize Pipes configuration in one place that always sets Submitter.EXECUTABLE","Prefer the 'path#linkname' form so the binary is also shipped via distributed cache"],"tags":["hadoop-pipes","job-submission","missing-config","native-binary","mapreduce"],"backgroundTag":"missing-required-config","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}