apache/druid · error · ISE

Incompatible strategy for type

Error message

Incompatible strategy for type[%s] already exists. Expected [%s], found [%s].

What it means

TypeStrategies.registerComplex() registers the serialization strategy for a complex type. If a strategy for the same complex type name is already registered with a different implementation class, it throws IllegalStateException to prevent silently swapping serializers, which would corrupt deserialization of existing segments.

Solutions

  1. Ensure only one implementation registers the strategy for that complex type name
  2. Remove duplicate/shaded jars providing conflicting TypeStrategy classes
  3. Align extension versions across the cluster so the same strategy class is used

Example fix

// before
ComplexMetrics.registerSerde("myType", new MyCustomSerde()); // conflicts with existing
// after
ComplexMetrics.registerSerde("myType", MyStandardSerde.class == alreadyRegistered.getClass()
    ? alreadyRegistered : new MyStandardSerde());
Defensive patterns

Strategy: validation

Validate before calling

TypeStrategy existing = ComplexMetrics.getSerdeForType(typeName); if (existing != null && !existing.getClass().equals(myStrategy.getClass())) { throw new ConflictingRegistration(typeName); }

Type guard

boolean isCompatible(TypeStrategy existing, TypeStrategy candidate) { return existing == null || existing.getClass().getName().equals(candidate.getClass().getName()); }

Try / catch

try { TypeStrategies.registerComplex(typeName, strategy); } catch (ISE e) { log.warn("Strategy already registered for %s, reusing existing", typeName); }

Prevention

When it happens

Trigger: Registering a complex type (e.g. via ComplexMetrics.registerSerDe or extension initialization) where another extension/classloader already registered a different TypeStrategy class for the same type name.

Common situations: Two extensions registering the same complex type name with different serializer implementations; duplicate classes on the classpath (shaded jars); Druid clusters with mixed extension versions.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/1ee3eccd5b42f01e. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/column/TypeStrategies.java:89

  /**
   * hmm... this might look familiar... (see ComplexMetrics)
   * <p>
   * Register a complex type name -> {@link TypeStrategy} mapping.
   * <p>
   * If the specified type name is already used and the supplied {@link TypeStrategy} is not of the
   * same type as the existing value in the map for said key, an {@link ISE} is thrown.
   *
   * @param strategy The {@link TypeStrategy} object to be associated with the 'type' in the map.
   */
  public static void registerComplex(String typeName, TypeStrategy<?> strategy)
  {
    Preconditions.checkNotNull(typeName);
    COMPLEX_STRATEGIES.compute(typeName, (key, value) -> {
      if (value == null) {
        return strategy;
      } else {
        if (!value.getClass().getName().equals(strategy.getClass().getName())) {
          throw new ISE(
              "Incompatible strategy for type[%s] already exists. Expected [%s], found [%s].",
              key,
              strategy.getClass().getName(),
              value.getClass().getName()
          );
        } else {
          return value;
        }
      }
    });
  }

  /**
   * Clear and set the 'null' byte of a nullable value to {@link TypeStrategies#IS_NULL_BYTE} to a {@link ByteBuffer} at
   * the supplied position. This method does not change the buffer position, limit, or mark, because it does not expect
   * to own the buffer given to it (i.e. buffer aggs)
   * <p>
   * Nullable types are stored with a leading byte to indicate if the value is null, followed by the value bytes

View on GitHub (pinned to 9b90983fd2)