apache/druid · error · IllegalStateException
Incompatible serializer for type
Error message
Incompatible serializer for type[%s] already exists. Expected [%s], found [%s].
What it means
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.
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.
Example fix
// before
ComplexMetrics.registerSerde("mySketch", new MySketchSerdeV2()); // conflicts with V1 already registered
// after
// keep the same class as the one already registered, or use a distinct type name:
ComplexMetrics.registerSerde("mySketchV2", new MySketchSerdeV2()); Defensive patterns
Strategy: validation
Validate before calling
ObjectStrategy<?> existing = ComplexMetrics.getSerdeForType("mySketch");
if (existing != null && !existing.getClass().equals(MySketchSerdeV2.class)) {
throw new IllegalStateException("Type mySketch already bound to " + existing.getClass().getName());
}
ComplexMetrics.registerSerde("mySketch", new MySketchSerdeV2()); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- written out already
- written out already
- Actual Row count mismatch. Expected
- Attempt to add row to swapped-out sink for segment
- Column capacity exceeded
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/b859a38ae1e823a6.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/serde/ComplexMetrics.java:60
* Register a serde name -> ComplexMetricSerde mapping.
*
* <p>
* If the specified serde key string is already used and the supplied ComplexMetricSerde is not of the same
* type as the existing value in the map for said key, an ISE is thrown.
* </p>
*
* @param type The serde name used as the key in the map.
* @param serde The ComplexMetricSerde object to be associated with the 'type' in the map.
*/
public static void registerSerde(String type, ComplexMetricSerde serde)
{
COMPLEX_SERIALIZERS.compute(type, (key, value) -> {
if (value == null) {
TypeStrategies.registerComplex(type, serde.getTypeStrategy());
return serde;
} else {
if (!value.getClass().getName().equals(serde.getClass().getName())) {
throw new ISE(
"Incompatible serializer for type[%s] already exists. Expected [%s], found [%s].",
key,
serde.getClass().getName(),
value.getClass().getName()
);
} else {
return value;
}
}
});
}
/**
* Unregister a serde name -> ComplexMetricSerde mapping.
*
* If the specified serde key string is not in use, does nothing.
*
* Only expected to be used in tests.View on GitHub (pinned to 9b90983fd2)