{"record":{"id":"a1bd3f6e7ef37e4d","repo":"apache/hadoop","slug":"type-mismatch-in-key-from-map-expected-keyclassn","errorCode":null,"errorMessage":"Type mismatch in key from map: expected {keyClassName}, received {actualKeyClassName}","messagePattern":"Type mismatch in key from map: expected (.+?), received (.+?)","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/mapred/MapTask.java","lineNumber":1097,"sourceCode":"      } finally {\n        spillLock.unlock();\n      }\n      if (sortSpillException != null) {\n        throw new IOException(\"Spill thread failed to initialize\",\n            sortSpillException);\n      }\n    }\n\n    /**\n     * Serialize the key, value to intermediate storage.\n     * When this method returns, kvindex must refer to sufficient unused\n     * storage to store one METADATA.\n     */\n    public synchronized void collect(K key, V value, final int partition\n                                     ) throws IOException {\n      reporter.progress();\n      if (key.getClass() != keyClass) {\n        throw new IOException(\"Type mismatch in key from map: expected \"\n                              + keyClass.getName() + \", received \"\n                              + key.getClass().getName());\n      }\n      if (value.getClass() != valClass) {\n        throw new IOException(\"Type mismatch in value from map: expected \"\n                              + valClass.getName() + \", received \"\n                              + value.getClass().getName());\n      }\n      if (partition < 0 || partition >= partitions) {\n        throw new IOException(\"Illegal partition for \" + key + \" (\" +\n            partition + \")\");\n      }\n      checkSpillException();\n      bufferRemaining -= METASIZE;\n      if (bufferRemaining <= 0) {\n        // start spill if the thread is not running and the soft limit has been\n        // reached\n        spillLock.lock();","sourceCodeStart":1079,"sourceCodeEnd":1115,"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/MapTask.java#L1079-L1115","documentation":"The sorting collector type-checks every key passed to OutputCollector.collect() / Context.write() with an exact getClass() comparison against the configured map-output key class (mapreduce.map.output.key.class, set via Job.setMapOutputKeyClass). When map() emits a key of a different runtime class - including a subclass - the map task fails with this IOException on the first offending record.","triggerScenarios":"Mapper emits key instances whose class differs from job.getMapOutputKeyClass(); the job never called setMapOutputKeyClass so it defaults to the final output key class while the mapper writes something else; old-API JobConf with a wrong mapred.mapoutput.keyclass value.","commonSituations":"Mapper generics edited without updating job setup; mapper emits Text while the input format's LongWritable key is still the default; chained mappers/combiners with different schemas; jobs ported between old and new APIs where output types changed.","solutions":["Call job.setMapOutputKeyClass(...) with exactly the class map() writes (and setMapOutputValueClass for the value)","Check the Mapper<K,V,K2,V2> generic signature and every context.write(...) in map() and cleanup()","If a combiner is configured, its input key type must match the map output key type - verify or remove it","Smoke-test with LocalJobRunner or a mapper unit test before cluster submission"],"exampleFix":"// before\npublic class UpperMapper extends Mapper<LongWritable, Text, Text, Text> { /* writes Text keys */ }\njob.setOutputKeyClass(Text.class);          // only final output classes set\njob.setOutputValueClass(Text.class);\n\n// after\njob.setMapOutputKeyClass(Text.class);       // what the mapper emits\njob.setMapOutputValueClass(Text.class);\njob.setOutputKeyClass(Text.class);          // what the reducer emits\njob.setOutputValueClass(Text.class);","handlingStrategy":"validation","validationCode":"// before job.submit(): mapper's generic K2/V2 must equal configured map-output classes\nType t = TokenMapper.class.getGenericSuperclass();\nif (t instanceof ParameterizedType) {\n  Type[] a = ((ParameterizedType) t).getActualTypeArguments();\n  if (!job.getMapOutputKeyClass().equals(a[2]) || !job.getMapOutputValueClass().equals(a[3])) {\n    throw new IllegalStateException(\"Mapper emits \" + a[2] + \",\" + a[3]\n        + \" but job configured \" + job.getMapOutputKeyClass() + \",\" + job.getMapOutputValueClass());\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set map-output key/value classes whenever they differ from the final output classes","Keep mapper generic parameters in sync with the classes actually constructed at emit sites","Run a one-record local integration test of each new mapper before cluster submission"],"tags":["hadoop","mapreduce","mapper","serialization","type-mismatch","configuration"],"backgroundTag":"serialization-type-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}