apache/druid · error · org.apache.druid.query.aggregation.AggregatorFactoryNotMergeableException

Incompatible aggregator factories, [this] and [other]

Error message

Incompatible aggregator factories, [this] and [other]

What it means

ApproximateHistogramAggregatorFactory.getMergingFactory() can only merge factories of the same runtime type and compatible parameters. When the incoming factory is not an ApproximateHistogramAggregatorFactory (or the cast fails the equality checks), it throws AggregatorFactoryNotMergeableException with the message 'Incompatible aggregator factories'. Two differently-typed aggregations over the same output name cannot be merged in distributed query results.

Source

Thrown at extensions-core/histogram/src/main/java/org/apache/druid/query/aggregation/histogram/ApproximateHistogramAggregatorFactory.java:211

  @Override
  public AggregatorFactory getMergingFactory(AggregatorFactory other) throws AggregatorFactoryNotMergeableException
  {
    if (other.getName().equals(this.getName()) && other instanceof ApproximateHistogramAggregatorFactory) {
      ApproximateHistogramAggregatorFactory castedOther = (ApproximateHistogramAggregatorFactory) other;

      return new ApproximateHistogramFoldingAggregatorFactory(
          name,
          name,
          Math.max(resolution, castedOther.resolution),
          numBuckets,
          Math.min(lowerLimit, castedOther.lowerLimit),
          Math.max(upperLimit, castedOther.upperLimit),
          finalizeAsBase64Binary
      );

    } else {
      throw new AggregatorFactoryNotMergeableException(this, other);
    }
  }

  @Override
  public Object deserialize(Object object)
  {
    if (object instanceof byte[]) {
      final ApproximateHistogram ah = ApproximateHistogram.fromBytes((byte[]) object);
      ah.setLowerLimit(lowerLimit);
      ah.setUpperLimit(upperLimit);

      return ah;
    } else if (object instanceof ByteBuffer) {
      final ApproximateHistogram ah = ApproximateHistogram.fromBytes((ByteBuffer) object);
      ah.setLowerLimit(lowerLimit);
      ah.setUpperLimit(upperLimit);

      return ah;

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Rename one of the aggregations so output names are unique (e.g. 'hist' vs 'sum')
  2. Ensure both sides of the merge use identical aggregator factory type and parameters (resolution, lowerLimit, upperLimit)
  3. Check queries for aggregation name collisions with post-aggregators or nested subquery columns
  4. If a rolling upgrade caused mismatched plans, align Druid versions/configs across nodes

Example fix

// before
AggregatorFactory a = new ApproximateHistogramAggregatorFactory("out", "col", ...);
AggregatorFactory b = new DoubleSumAggregatorFactory("out", "col"); // merge throws
// after
AggregatorFactory a = new ApproximateHistogramAggregatorFactory("hist", "col", ...);
AggregatorFactory b = new DoubleSumAggregatorFactory("sum", "col");
Defensive patterns

Strategy: validation

Validate before calling

if (!aggregationNameToFactory.isEmpty() && new Set(aggregationNames).size !== aggregationNames.length) {
  throw new IllegalArgumentException("Duplicate aggregation output names cause merge failures");
}

Type guard

null

Try / catch

try {
  merged = factory.getMergingFactory(other);
} catch (AggregatorFactoryNotMergeableException e) {
  log.error("Aggregation output names must be unique and same-typed across nodes", e);
  throw e;
}

Prevention

When it happens

Trigger: getMergingFactory(other) is called where other's equality check against this factory fails — e.g. merging results from two nodes that aggregated the same output name with different aggregation types (approxHistogram vs another aggregator type).

Common situations: Two subqueries/hashes producing aggregations with the same output column name but different types; a groupBy or timeseries with a post-aggregation name colliding with an aggregation name; mismatched query plans across historical nodes after a config/version change.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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