apache/druid · error · IllegalArgumentException
Indices to merge contained metric
Error message
Indices to merge contained metric[%s], but requested metrics did not
What it means
During IndexMergerBase.merge, the merged metric list (requested/aggregator spec) is aligned with the metrics actually present in the input segments. If an input segment contains a metric whose name has no matching AggregatorFactory in sortedMetricAggs, the slot is null and merge fails: you asked to merge segments whose schema includes metrics your aggregator spec does not request.
Solutions
- Include an AggregatorFactory for every metric present in the input segments (inspect segment metadata to list them)
- Re-ingest the underlying data with the new, smaller metric set instead of merging mismatched segments
- Align compaction/merge specs with the schema of all segments in the target interval
Example fix
// before
AggregatorFactory[] aggs = { new LongSumAggregatorFactory("count", "rows") };
merger.merge(QueryableIndex... , false, aggs, ...); // inputs also have 'sum'
// after
AggregatorFactory[] aggs = {
new LongSumAggregatorFactory("count", "rows"),
new DoubleSumAggregatorFactory("sum", "sum") // matches existing segment metric
};
merger.merge(indices, false, aggs, ...); Defensive patterns
Strategy: validation
Validate before calling
Set<String> segmentMetrics = getMetricNamesFromSegments(indices); // e.g. via SegmentMetadataQuery
Set<String> requested = Arrays.stream(aggs).map(AggregatorFactory::getName)
.collect(Collectors.toSet());
if (!segmentMetrics.equals(requested)) {
throw new IllegalStateException("Metric mismatch: segments have " + segmentMetrics
+ " but merge spec has " + requested);
} Try / catch
try {
merger.merge(indices, rollup, aggs, outDir, indexSpec, progress, null);
} catch (IAE e) {
if (e.getMessage().contains("requested metrics did not")) {
// rebuild aggregator list from segment metadata and retry
}
} Prevention
- Introspect segment metadata for all metric names before constructing the merge aggregator list
- Keep ingestion specs backward compatible when dropping metrics, or re-ingest instead of merging
- Use compaction tooling that derives aggregators from existing segment schemas automatically
When it happens
Trigger: Merging persisted segments that were built with more aggregators than the current AggregatorFactory[] passed to merge — e.g. merging segments containing a 'sum' metric with an aggregators array that omits it; schema drift between ingestion runs.
Common situations: Re-merging old segments after changing the ingestion spec's metricsSpec; dropping a metric from the spec while older segments still contain it; coordinator-driven compaction with an outdated aggregators list.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- AggregatorFactoryNotMergeableException
- AggregatorFactoryNotMergeableException
- AggregatorFactoryNotMergeableException(this, other)
- bf1Length does not match bf2Length
- Cannot merge columns of type
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/584fc321e03f87b3.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/IndexMergerBase.java:423
final AggregatorFactory[] sortedMetricAggs = new AggregatorFactory[mergedMetrics.size()];
for (AggregatorFactory metricAgg : metricAggs) {
int metricIndex = mergedMetrics.indexOf(metricAgg.getName());
/*
If metricIndex is negative, one of the metricAggs was not present in the union of metrics from the indices
we are merging
*/
if (metricIndex > -1) {
sortedMetricAggs[metricIndex] = metricAgg;
}
}
/*
If there is nothing at sortedMetricAggs[i], then we did not have a metricAgg whose name matched the name
of the ith element of mergedMetrics. I.e. There was a metric in the indices to merge that we did not ask for.
*/
for (int i = 0; i < sortedMetricAggs.length; i++) {
if (sortedMetricAggs[i] == null) {
throw new IAE("Indices to merge contained metric[%s], but requested metrics did not", mergedMetrics.get(i));
}
}
for (int i = 0; i < mergedMetrics.size(); i++) {
if (!sortedMetricAggs[i].getName().equals(mergedMetrics.get(i))) {
throw new IAE(
"Metric mismatch, index[%d] [%s] != [%s]",
i,
sortedMetricAggs[i].getName(),
mergedMetrics.get(i)
);
}
}
Function<List<TransformableRowIterator>, TimeAndDimsIterator> rowMergerFn;
if (rollup) {
rowMergerFn = rowIterators -> new RowCombiningTimeAndDimsIterator(rowIterators, sortedMetricAggs, mergedMetrics);
} else {View on GitHub (pinned to 9b90983fd2)