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

  1. Include an AggregatorFactory for every metric present in the input segments (inspect segment metadata to list them)
  2. Re-ingest the underlying data with the new, smaller metric set instead of merging mismatched segments
  3. 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

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


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)