{"record":{"id":"b859a38ae1e823a6","repo":"apache/druid","slug":"incompatible-serializer-for-type-s-already-exist","errorCode":null,"errorMessage":"Incompatible serializer for type[%s] already exists. Expected [%s], found [%s].","messagePattern":"Incompatible serializer for type\\[(.+?)\\] already exists\\. Expected \\[(.+?)\\], found \\[(.+?)\\]\\.","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/serde/ComplexMetrics.java","lineNumber":60,"sourceCode":"   * Register a serde name -> ComplexMetricSerde mapping.\n   *\n   * <p>\n   * If the specified serde key string is already used and the supplied ComplexMetricSerde is not of the same\n   * type as the existing value in the map for said key, an ISE is thrown.\n   * </p>\n   *\n   * @param type The serde name used as the key in the map.\n   * @param serde The ComplexMetricSerde object to be associated with the 'type' in the map.\n   */\n  public static void registerSerde(String type, ComplexMetricSerde serde)\n  {\n    COMPLEX_SERIALIZERS.compute(type, (key, value) -> {\n      if (value == null) {\n        TypeStrategies.registerComplex(type, serde.getTypeStrategy());\n        return serde;\n      } else {\n        if (!value.getClass().getName().equals(serde.getClass().getName())) {\n          throw new ISE(\n              \"Incompatible serializer for type[%s] already exists. Expected [%s], found [%s].\",\n              key,\n              serde.getClass().getName(),\n              value.getClass().getName()\n          );\n        } else {\n          return value;\n        }\n      }\n    });\n  }\n\n  /**\n   * Unregister a serde name -> ComplexMetricSerde mapping.\n   *\n   * If the specified serde key string is not in use, does nothing.\n   *\n   * Only expected to be used in tests.","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/serde/ComplexMetrics.java#L42-L78","documentation":"ComplexMetrics.registerSerde registers an ObjectStrategy-based serializer for a named complex type (e.g. \"hyperUnique\", \"quantilesDoublesSketch\") in a static registry. If a serde for the same type name is already registered from a DIFFERENT class, registration fails with this ISE, because silently swapping serializers would corrupt reading of existing segments. Registering the same class twice is idempotent and allowed.","triggerScenarios":"Calling ComplexMetrics.registerSerde(typeName, serde) when the static COMPLEX_SERIALIZERS map already holds an entry for typeName whose serde class differs from the new serde's class.","commonSituations":"Loading two extensions that both register a serde for the same complex type name (e.g. two custom sketch extensions registering the same typeName); a classpath containing duplicate/conflicting extension jars; renaming or refactoring a serde class while an old segment's Druid version re-registers the old class under the same name; calling registerSerde again with a new serializer implementation for the same type.","solutions":["Identify the two extensions/jars registering the same complex type name and remove the duplicate or conflicting dependency from the classpath.","Ensure you register exactly one serde class per type name at startup; guard registration so it happens once.","If you intentionally changed the serde implementation, use a new complex type name instead of reusing the old one, or revert to the original class.","Check druid.extensions.loadList and extension directories for jars that register the same type."],"exampleFix":"// before\nComplexMetrics.registerSerde(\"mySketch\", new MySketchSerdeV2()); // conflicts with V1 already registered\n// after\n// keep the same class as the one already registered, or use a distinct type name:\nComplexMetrics.registerSerde(\"mySketchV2\", new MySketchSerdeV2());","handlingStrategy":"validation","validationCode":"ObjectStrategy<?> existing = ComplexMetrics.getSerdeForType(\"mySketch\");\nif (existing != null && !existing.getClass().equals(MySketchSerdeV2.class)) {\n    throw new IllegalStateException(\"Type mySketch already bound to \" + existing.getClass().getName());\n}\nComplexMetrics.registerSerde(\"mySketch\", new MySketchSerdeV2());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register each complex type name exactly once, in a single well-known initialization point (extension init).","Use type names namespaced to your extension to avoid collisions with other extensions.","Audit extension load lists for overlapping complex-type registrations."],"tags":["druid","segment","serialization","startup","registry-conflict"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}