apache/hadoop · error · IllegalArgumentException

Id {} exists but maps to {} and not {}

Error message

Id {} exists but maps to {} and not {}

What it means

The mirror check in AbstractMapWritable.addToMap(clazz, id): if the byte id is already bound to a different class, IllegalArgumentException reports both the existing class and the attempted one. Together with the class->id check it guarantees the two maps stay bijective; violation means two classes claim the same wire id.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/AbstractMapWritable.java:79

  byte getNewClasses() {
    return newClasses;
  }

  /**
   * Used to add "predefined" classes and by Writable to copy "new" classes.
   */
  private synchronized void addToMap(Class<?> clazz, byte id) {
    if (classToIdMap.containsKey(clazz)) {
      byte b = classToIdMap.get(clazz);
      if (b != id) {
        throw new IllegalArgumentException ("Class " + clazz.getName() +
          " already registered but maps to " + b + " and not " + id);
      }
    }
    if (idToClassMap.containsKey(id)) {
      Class<?> c = idToClassMap.get(id);
      if (!c.equals(clazz)) {
        throw new IllegalArgumentException("Id " + id + " exists but maps to " +
            c.getName() + " and not " + clazz.getName());
      }
    }
    classToIdMap.put(clazz, id);
    idToClassMap.put(id, clazz);
  }
  
  /**
   * Add a Class to the maps if it is not already present.
   * @param clazz clazz.
   */
  protected synchronized void addToMap(Class<?> clazz) {
    if (classToIdMap.containsKey(clazz)) {
      return;
    }
    if (newClasses + 1 > Byte.MAX_VALUE) {
      throw new IndexOutOfBoundsException("adding an additional class would" +
      " exceed the maximum number allowed");

View on GitHub (pinned to 2add963021)

Solutions

  1. Pick custom fixed ids that do not collide with -127..-113 (the predefined range printed in the AbstractMapWritable constructor)
  2. Make registration order deterministic: static, fixed assignments rather than order-of-first-use
  3. Bump to a fresh set of ids (and drain queues) when changing registrations during upgrades
Defensive patterns

Strategy: try-catch

Validate before calling

// choose custom ids outside the predefined -127..-113 range and unique per class
static final byte ID_TYPE_A = (byte) -100; // verify -100 is not already used

Try / catch

try {
  map.readFields(in);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("exists but maps to")) {
    // the byte id means a different class on the writer: version/registration mismatch
  }
}

Prevention

When it happens

Trigger: A custom registration picks an id that collides with a predefined one (AbstractMapWritable's constructor binds -127 through -113); deserializing a stream where the sender assigned that id to a different class because registration order differed; hand-written readFields mixing tables.

Common situations: Choosing custom ids like -120 without checking the predefined table; cluster nodes running builds where a new class was inserted in the middle of the registration list, shifting ids.

Related errors


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