{"record":{"id":"006c04dd69577b25","repo":"apache/hadoop","slug":"class-already-registered-but-maps-to-and-not","errorCode":null,"errorMessage":"Class {} already registered but maps to {} and not {}","messagePattern":"Class (.+?) already registered but maps to (.+?) and not (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/AbstractMapWritable.java","lineNumber":72,"sourceCode":"  @VisibleForTesting\n  Map<Byte, Class<?>> idToClassMap = new ConcurrentHashMap<Byte, Class<?>>();\n  \n  /* The number of new classes (those not established by the constructor) */\n  private volatile byte newClasses = 0;\n  \n  /** @return the number of known classes */\n  byte getNewClasses() {\n    return newClasses;\n  }\n\n  /**\n   * Used to add \"predefined\" classes and by Writable to copy \"new\" classes.\n   */\n  private synchronized void addToMap(Class<?> clazz, byte id) {\n    if (classToIdMap.containsKey(clazz)) {\n      byte b = classToIdMap.get(clazz);\n      if (b != id) {\n        throw new IllegalArgumentException (\"Class \" + clazz.getName() +\n          \" already registered but maps to \" + b + \" and not \" + id);\n      }\n    }\n    if (idToClassMap.containsKey(id)) {\n      Class<?> c = idToClassMap.get(id);\n      if (!c.equals(clazz)) {\n        throw new IllegalArgumentException(\"Id \" + id + \" exists but maps to \" +\n            c.getName() + \" and not \" + clazz.getName());\n      }\n    }\n    classToIdMap.put(clazz, id);\n    idToClassMap.put(id, clazz);\n  }\n  \n  /**\n   * Add a Class to the maps if it is not already present.\n   * @param clazz clazz.\n   */","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/AbstractMapWritable.java#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Register custom classes with fixed, agreed byte ids (in a static initializer or constructor) so every node computes the same table","Never re-register the predefined classes (ids -127..-113 assigned in the AbstractMapWritable constructor) with different ids","Ensure writers and readers run the same version of your Writable class during and after upgrades"],"exampleFix":"// before: instance-level registration, ids depend on put order\nclass MyMap extends MapWritable { }\n\n// after: fixed ids, identical on every node\nclass MyMap extends MapWritable {\n  static { /* done in ctor of subclass */ }\n  MyMap() {\n    put(MyType.class, (byte) -100); // via protected addToMap(MyType.class, (byte)-100)\n  }\n}","handlingStrategy":"try-catch","validationCode":"// deterministic registration: fixed ids in the subclass constructor\nclass MyMapWritable extends MapWritable {\n  MyMapWritable() {\n    addToMap(TypeA.class, (byte) -100);\n    addToMap(TypeB.class, (byte) -101);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  map.put(key, value);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"already registered but maps to\")) {\n    // registration tables diverged: rebuild/refresh the map instead of mixing entries\n  }\n}","preventionTips":["Assign fixed byte ids to custom Writable types; never rely on first-use order","Do not re-register predefined classes (ids -127..-113) with new ids","Keep writers and readers on the same subclass version across a rolling upgrade"],"tags":["hadoop","serialization","writable","mapwritable","ipc"],"backgroundTag":"writable-class-id-conflict","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}