apache/druid · error · AggregatorFactoryNotMergeableException
AggregatorFactoryNotMergeableException
Error message
AggregatorFactoryNotMergeableException
What it means
SimpleFloatAggregatorFactory.getMergingFactory throws AggregatorFactoryNotMergeableException when the other factory's name or class does not match this one. Druid merges partial results across segments only when both factories are the same class (float-based aggregators) and share the same output name. A mismatch means the query is asking to combine a float aggregation with something that cannot be combined into it.
Source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/SimpleFloatAggregatorFactory.java:183
{
return object;
}
@Override
public List<String> requiredFields()
{
return fieldName != null
? Collections.singletonList(fieldName)
: fieldExpression.get().analyzeInputs().getRequiredBindingsList();
}
@Override
public AggregatorFactory getMergingFactory(AggregatorFactory other) throws AggregatorFactoryNotMergeableException
{
if (other.getName().equals(this.getName()) && this.getClass() == other.getClass()) {
return getCombiningFactory();
} else {
throw new AggregatorFactoryNotMergeableException(this, other);
}
}
@Override
public int hashCode()
{
return Objects.hash(fieldName, expression, name);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}View on GitHub (pinned to 9b90983fd2)
Solutions
- Align the output names of the float aggregators on both sides of the merge
- Use the same aggregator class (floatSum/floatMin/floatMax etc.) on both sides
- Adjust the query or ingestion spec so the same output name always refers to the same float-based aggregation
- If schema drifted, re-run the query with explicit numeric casts or re-ingest data to a consistent type
Example fix
// before
{ type: "floatSum", name: "s" } vs { type: "doubleSum", name: "s" }
// after
{ type: "floatSum", name: "s" } on both shards / subquery and outer query Defensive patterns
Strategy: validation
Validate before calling
boolean mergeable(AggregatorFactory a, AggregatorFactory b) {
return a.getName().equals(b.getName()) && a.getClass() == b.getClass();
} Type guard
boolean isMergeableFloatPair(AggregatorFactory other, SimpleFloatAggregatorFactory self) {
return other instanceof SimpleFloatAggregatorFactory && other.getName().equals(self.getName());
} Try / catch
try {
AggregatorFactory merged = factory.getMergingFactory(other);
} catch (AggregatorFactoryNotMergeableException e) {
LOGGER.warn(e, "Non-mergeable float aggregators: %s vs %s", e.getFactory1(), e.getFactory2());
} Prevention
- Never reuse the same output name for aggregators of different numeric types
- Keep float aggregators consistent between subquery and outer query layers
- Validate ingestion schema changes for metric type drift (float -> double)
- Run merge-sensitive queries against multi-segment datasources in tests
When it happens
Trigger: Calling getMergingFactory(other) with an other whose getName() differs from this factory's name, or whose class is not SimpleFloatAggregatorFactory (e.g. a double or long aggregator), typically during distributed query merging across multiple segments.
Common situations: Mixing float and double aggregators under one output name in a multi-segment query; schema changes between ingestion rounds that changed an aggregator's numeric type; subquery + outer query where the same name maps to different aggregator types.
Related errors
- AggregatorFactoryNotMergeableException
- AggregatorFactoryNotMergeableException
- Emit called unexpectedly before service start
- Got an exception while parsing file [%s]
- Unable to copy key [%s] to file [%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/12fa65dff5fea9c7.
Report an issue: GitHub.