apache/druid · error · AggregatorFactoryNotMergeableException
AggregatorFactoryNotMergeableException
Error message
AggregatorFactoryNotMergeableException
What it means
SimpleLongAggregatorFactory.getMergingFactory throws AggregatorFactoryNotMergeableException when the other factory has a different name or a different class. Native queries merge partial aggregation results from each segment; this only works if both factories are identical long-based aggregators with the same output name. The exception tells the planner it cannot produce a combined factory.
Source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/SimpleLongAggregatorFactory.java:186
{
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
- Ensure both sides use the same output name for the long aggregator
- Use identical long aggregator classes (longSum/longMin/longMax/longFirst/longAny) on both sides
- Rewrite the query to align inner and outer aggregations, or let the subquery perform its own final aggregation (use finalizeOuterAggregate=true where appropriate)
- Re-ingest or normalize schema if historical segments use a different metric type under the same name
Example fix
// before inner: longSum s ; outer: doubleSum s // after inner: longSum s ; outer: longSum s (or rename the outer metric)
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 isMergeableLongPair(AggregatorFactory other, SimpleLongAggregatorFactory self) {
return other instanceof SimpleLongAggregatorFactory && other.getName().equals(self.getName());
} Try / catch
try {
AggregatorFactory merged = factory.getMergingFactory(other);
} catch (AggregatorFactoryNotMergeableException e) {
LOGGER.warn(e, "Non-mergeable long aggregators: %s vs %s", e.getFactory1(), e.getFactory2());
} Prevention
- Align long aggregation names between inner and outer queries
- Avoid mixing long/float/double aggregators under one output name
- Normalize schema across segments (or re-ingest) when metric types change
- Prefer letting subqueries finalize their own aggregation instead of cross-layer merging
When it happens
Trigger: Query fan-out across segments/subqueries where the same output name maps to a SimpleLongAggregatorFactory on one side and a different aggregator class or name on the other, causing merge code to call getMergingFactory.
Common situations: Subquery/outer query with mismatched long aggregation names; ingestion specs changed a metric from long to float/double over time; inline datasources (JOIN results) that don't carry the same aggregator setup as base segments.
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/5acbc406efd5127e.
Report an issue: GitHub.