apache/hadoop · error · IllegalArgumentException

Class {} already registered but maps to {} and not {}

Error message

Class {} already registered but maps to {} and not {}

What it means

AbstractMapWritable keeps two maps (class -> byte id and id -> class). addToMap(clazz, id) throws IllegalArgumentException when the class is already registered under a different id. This happens when a Writable map's registrations are not consistent - e.g., a subclass re-registers a predefined class with a new id, or deserializing data written by a peer whose registration table differs.

Source

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

  @VisibleForTesting
  Map<Byte, Class<?>> idToClassMap = new ConcurrentHashMap<Byte, Class<?>>();
  
  /* The number of new classes (those not established by the constructor) */
  private volatile byte newClasses = 0;
  
  /** @return the number of known classes */
  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.
   */

View on GitHub (pinned to 2add963021)

Solutions

  1. Register custom classes with fixed, agreed byte ids (in a static initializer or constructor) so every node computes the same table
  2. Never re-register the predefined classes (ids -127..-113 assigned in the AbstractMapWritable constructor) with different ids
  3. Ensure writers and readers run the same version of your Writable class during and after upgrades

Example fix

// before: instance-level registration, ids depend on put order
class MyMap extends MapWritable { }

// after: fixed ids, identical on every node
class MyMap extends MapWritable {
  static { /* done in ctor of subclass */ }
  MyMap() {
    put(MyType.class, (byte) -100); // via protected addToMap(MyType.class, (byte)-100)
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// deterministic registration: fixed ids in the subclass constructor
class MyMapWritable extends MapWritable {
  MyMapWritable() {
    addToMap(TypeA.class, (byte) -100);
    addToMap(TypeB.class, (byte) -101);
  }
}

Try / catch

try {
  map.put(key, value);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("already registered but maps to")) {
    // registration tables diverged: rebuild/refresh the map instead of mixing entries
  }
}

Prevention

When it happens

Trigger: A custom MapWritable subclass constructor calls addToMap(MyClass.class, (byte)5) while also putting MyClass values into a map that dynamically assigns ids; readFields() on wire bytes where the sender registered the class with another id; copying between map writables with different registration histories.

Common situations: Rolling upgrades where writer and reader run different application versions with renumbered registrations; ad-hoc registration of classes in instance constructors instead of fixed static ids.

Related errors


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