{"record":{"id":"66ad21f9e0b53547","repo":"apache/hadoop","slug":"is-incompatible-with-mode","errorCode":null,"errorMessage":"{} is incompatible with {} mode.","messagePattern":"(.+?) is incompatible with (.+?) mode\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/Job.java","lineNumber":1361,"sourceCode":"   */\n  public void setProfileParams(String value) {\n    ensureState(JobState.DEFINE);\n    conf.setProfileParams(value);\n  }\n\n  /**\n   * Set the ranges of maps or reduces to profile. setProfileEnabled(true) \n   * must also be called.\n   * @param newValue a set of integer ranges of the map ids\n   */\n  public void setProfileTaskRange(boolean isMap, String newValue) {\n    ensureState(JobState.DEFINE);\n    conf.setProfileTaskRange(isMap, newValue);\n  }\n\n  private void ensureNotSet(String attr, String msg) throws IOException {\n    if (conf.get(attr) != null) {\n      throw new IOException(attr + \" is incompatible with \" + msg + \" mode.\");\n    }    \n  }\n  \n  /**\n   * Sets the flag that will allow the JobTracker to cancel the HDFS delegation\n   * tokens upon job completion. Defaults to true.\n   */\n  public void setCancelDelegationTokenUponJobCompletion(boolean value) {\n    ensureState(JobState.DEFINE);\n    conf.setBoolean(JOB_CANCEL_DELEGATION_TOKEN, value);\n  }\n\n  /**\n   * Default to the new APIs unless they are explicitly set or the old mapper or\n   * reduce attributes are used.\n   * @throws IOException if the configuration is inconsistent\n   */\n  private void setUseNewAPI() throws IOException {","sourceCodeStart":1343,"sourceCodeEnd":1379,"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/Job.java#L1343-L1379","documentation":"During submit(), Job.setUseNewAPI() decides whether map/reduce stages run on the new org.apache.hadoop.mapreduce API or the old org.apache.hadoop.mapred API. It picks a mode per stage and calls ensureNotSet for the other generation's keys (e.g. 'mapred.mapper.class' vs mapreduce.job.map.class, 'mapred.input.format.class' vs INPUT_FORMAT_CLASS_ATTR). If a key from the wrong generation is set, it throws IOException('<attr> is incompatible with <new map API|map compatibility|new reduce API|reduce compatibility> mode.') naming the offending property.","triggerScenarios":"Loading a job.xml written for the old mapred API and then calling new-API setters (job.setMapperClass) on the same conf; setting 'mapred.input.format.class'/'mapred.partitioner.class' while INPUT_FORMAT_CLASS_ATTR/MAP_CLASS_ATTR are also present; setting 'mapred.output.format.class' when the new OUTPUT_FORMAT_CLASS_ATTR is set and numReduceTasks is 0 (the reduce-mode branch only runs with reduces, so map-only jobs check output format in the map branch).","commonSituations":"Migrating Hadoop 1.x jobs to 2.x/3.x; third-party frameworks that write old key names; copying configuration snippets that mix JobConf-style and Job-style examples; leftover keys in cluster-wide mapred-site.xml.","solutions":["Choose one API generation: conf.unset(\"mapred.mapper.class\"), conf.unset(\"mapred.input.format.class\"), etc. for every old key you replace with new-API setters","Before submit(), scan both key families and fail fast with your own message listing duplicates","When loading legacy job.xml files, unset old keys for any slot you set programmatically","Check mapreduce partitions too: if numReduceTasks != 0 the partitioner keys are also mutually exclusive"],"exampleFix":"// before\nconf.set(\"mapred.mapper.class\", MyOldMapper.class.getName());\njob.setMapperClass(MyNewMapper.class); // sets mapreduce.job.map.class\njob.submit(); // IOException: mapred.mapper.class is incompatible with new map API mode.\n\n// after\nconf.unset(\"mapred.mapper.class\");\njob.setMapperClass(MyNewMapper.class);\njob.submit();","handlingStrategy":"validation","validationCode":"// fail fast on mixed old/new API keys before submit()\nString[][] pairs = {\n  {\"mapred.mapper.class\", \"mapreduce.job.map.class\"},\n  {\"mapred.input.format.class\", \"mapreduce.job.inputformat.class\"},\n  {\"mapred.reducer.class\", \"mapreduce.job.reduce.class\"},\n  {\"mapred.output.format.class\", \"mapreduce.job.outputformat.class\"},\n  {\"mapred.partitioner.class\", \"mapreduce.job.partitioner.class\"}\n};\nfor (String[] p : pairs) {\n  if (conf.get(p[0]) != null && conf.get(p[1]) != null) {\n    throw new IOException(\"Both \" + p[0] + \" and \" + p[1] + \" are set; unset one API generation\");\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one API generation per job and lint the conf for the other generation's keys","unset() old keys when loading legacy job.xml files","Watch map-only jobs: output-format keys are checked in the map branch when reduces == 0"],"tags":["configuration","api-compatibility","mapred-api","job-submission","mapreduce"],"backgroundTag":"conflicting-config-keys","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}