{"record":{"id":"584fc321e03f87b3","repo":"apache/druid","slug":"indices-to-merge-contained-metric-s-but-request","errorCode":null,"errorMessage":"Indices to merge contained metric[%s], but requested metrics did not","messagePattern":"Indices to merge contained metric\\[(.+?)\\], but requested metrics did not","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/IndexMergerBase.java","lineNumber":423,"sourceCode":"    final AggregatorFactory[] sortedMetricAggs = new AggregatorFactory[mergedMetrics.size()];\n    for (AggregatorFactory metricAgg : metricAggs) {\n      int metricIndex = mergedMetrics.indexOf(metricAgg.getName());\n      /*\n        If metricIndex is negative, one of the metricAggs was not present in the union of metrics from the indices\n        we are merging\n       */\n      if (metricIndex > -1) {\n        sortedMetricAggs[metricIndex] = metricAgg;\n      }\n    }\n\n    /*\n      If there is nothing at sortedMetricAggs[i], then we did not have a metricAgg whose name matched the name\n      of the ith element of mergedMetrics. I.e. There was a metric in the indices to merge that we did not ask for.\n     */\n    for (int i = 0; i < sortedMetricAggs.length; i++) {\n      if (sortedMetricAggs[i] == null) {\n        throw new IAE(\"Indices to merge contained metric[%s], but requested metrics did not\", mergedMetrics.get(i));\n      }\n    }\n\n    for (int i = 0; i < mergedMetrics.size(); i++) {\n      if (!sortedMetricAggs[i].getName().equals(mergedMetrics.get(i))) {\n        throw new IAE(\n            \"Metric mismatch, index[%d] [%s] != [%s]\",\n            i,\n            sortedMetricAggs[i].getName(),\n            mergedMetrics.get(i)\n        );\n      }\n    }\n\n    Function<List<TransformableRowIterator>, TimeAndDimsIterator> rowMergerFn;\n    if (rollup) {\n      rowMergerFn = rowIterators -> new RowCombiningTimeAndDimsIterator(rowIterators, sortedMetricAggs, mergedMetrics);\n    } else {","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/IndexMergerBase.java#L405-L441","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nAggregatorFactory[] aggs = { new LongSumAggregatorFactory(\"count\", \"rows\") };\nmerger.merge(QueryableIndex... , false, aggs, ...); // inputs also have 'sum'\n// after\nAggregatorFactory[] aggs = {\n    new LongSumAggregatorFactory(\"count\", \"rows\"),\n    new DoubleSumAggregatorFactory(\"sum\", \"sum\") // matches existing segment metric\n};\nmerger.merge(indices, false, aggs, ...);","handlingStrategy":"validation","validationCode":"Set<String> segmentMetrics = getMetricNamesFromSegments(indices); // e.g. via SegmentMetadataQuery\nSet<String> requested = Arrays.stream(aggs).map(AggregatorFactory::getName)\n    .collect(Collectors.toSet());\nif (!segmentMetrics.equals(requested)) {\n  throw new IllegalStateException(\"Metric mismatch: segments have \" + segmentMetrics\n      + \" but merge spec has \" + requested);\n}","typeGuard":null,"tryCatchPattern":"try {\n  merger.merge(indices, rollup, aggs, outDir, indexSpec, progress, null);\n} catch (IAE e) {\n  if (e.getMessage().contains(\"requested metrics did not\")) {\n    // rebuild aggregator list from segment metadata and retry\n  }\n}","preventionTips":["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"],"tags":["druid","index-merger","merge","schema-drift","metrics"],"backgroundTag":"schema-validation-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}