apache/hadoop · error · IOException

Type mismatch in key from map: expected

Error message

Type mismatch in key from map: expected {keyClassName}, received {actualKeyClassName}

What it means

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.

Solutions

  1. Call job.setMapOutputKeyClass(...) with exactly the class map() writes (and setMapOutputValueClass for the value)
  2. Check the Mapper<K,V,K2,V2> generic signature and every context.write(...) in map() and cleanup()
  3. If a combiner is configured, its input key type must match the map output key type - verify or remove it
  4. Smoke-test with LocalJobRunner or a mapper unit test before cluster submission

Example fix

// before
public class UpperMapper extends Mapper<LongWritable, Text, Text, Text> { /* writes Text keys */ }
job.setOutputKeyClass(Text.class);          // only final output classes set
job.setOutputValueClass(Text.class);

// after
job.setMapOutputKeyClass(Text.class);       // what the mapper emits
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);          // what the reducer emits
job.setOutputValueClass(Text.class);
Defensive patterns

Strategy: validation

Validate before calling

// before job.submit(): mapper's generic K2/V2 must equal configured map-output classes
Type t = TokenMapper.class.getGenericSuperclass();
if (t instanceof ParameterizedType) {
  Type[] a = ((ParameterizedType) t).getActualTypeArguments();
  if (!job.getMapOutputKeyClass().equals(a[2]) || !job.getMapOutputValueClass().equals(a[3])) {
    throw new IllegalStateException("Mapper emits " + a[2] + "," + a[3]
        + " but job configured " + job.getMapOutputKeyClass() + "," + job.getMapOutputValueClass());
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/a1bd3f6e7ef37e4d. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/MapTask.java:1097

      } finally {
        spillLock.unlock();
      }
      if (sortSpillException != null) {
        throw new IOException("Spill thread failed to initialize",
            sortSpillException);
      }
    }

    /**
     * Serialize the key, value to intermediate storage.
     * When this method returns, kvindex must refer to sufficient unused
     * storage to store one METADATA.
     */
    public synchronized void collect(K key, V value, final int partition
                                     ) throws IOException {
      reporter.progress();
      if (key.getClass() != keyClass) {
        throw new IOException("Type mismatch in key from map: expected "
                              + keyClass.getName() + ", received "
                              + key.getClass().getName());
      }
      if (value.getClass() != valClass) {
        throw new IOException("Type mismatch in value from map: expected "
                              + valClass.getName() + ", received "
                              + value.getClass().getName());
      }
      if (partition < 0 || partition >= partitions) {
        throw new IOException("Illegal partition for " + key + " (" +
            partition + ")");
      }
      checkSpillException();
      bufferRemaining -= METASIZE;
      if (bufferRemaining <= 0) {
        // start spill if the thread is not running and the soft limit has been
        // reached
        spillLock.lock();

View on GitHub (pinned to 2add963021)