apache/druid · error · SegmentValidationException

Metric names differ. Expected

Error message

Metric names differ. Expected [%s] found [%s]

What it means

IndexIO.validateTwoSegments also compares metric (aggregator) name sets between the two segment adapters. This SegmentValidationException is thrown when the metric name sets differ, indicating the segments have different aggregator columns.

Solutions

  1. Compare the metric sets in the message and identify the missing/extra metric.
  2. Make both ingestion/compaction specs declare the same aggregators and rebuild the divergent segment.
  3. If a metric was intentionally added/renamed, validate against the updated reference segment, not the old one.
  4. Check query-time metric availability (queries depending on the missing metric will fail) after fixing.
Defensive patterns

Strategy: validation

Validate before calling

Set<String> met1 = Sets.newHashSet(adapter1.getMetricNames());
Set<String> met2 = Sets.newHashSet(adapter2.getMetricNames());
if (!met1.equals(met2)) {
  throw new IllegalStateException("Metric sets differ: " + met1 + " vs " + met2);
}

Try / catch

try {
  io.validateTwoSegments(adapter1, adapter2);
} catch (SegmentValidationException e) {
  if (e.getMessage().startsWith("Metric names differ")) {
    log.error("Aggregator mismatch between segments: %s", e.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: validateTwoSegments where adapter1.getMetricNames() and adapter2.getMetricNames() yield unequal sets — a metric present in one segment but missing in the other.

Common situations: Changing the aggregators list between ingestion runs; a metricsInSpec typo or renamed aggregator; compaction producing different metrics than the original segment; comparing segments from different datasources or specs.

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/51c47ac236a8d306. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/IndexIO.java:172

          "Row count mismatch. Expected [%d] found [%d]",
          adapter1.getNumRows(),
          adapter2.getNumRows()
      );
    }
    {
      final Set<String> dimNames1 = Sets.newHashSet(adapter1.getDimensionNames(true));
      final Set<String> dimNames2 = Sets.newHashSet(adapter2.getDimensionNames(true));
      if (!dimNames1.equals(dimNames2)) {
        throw new SegmentValidationException(
            "Dimension names differ. Expected [%s] found [%s]",
            dimNames1,
            dimNames2
        );
      }
      final Set<String> metNames1 = Sets.newHashSet(adapter1.getMetricNames());
      final Set<String> metNames2 = Sets.newHashSet(adapter2.getMetricNames());
      if (!metNames1.equals(metNames2)) {
        throw new SegmentValidationException("Metric names differ. Expected [%s] found [%s]", metNames1, metNames2);
      }
    }
    try (
        final RowIterator it1 = adapter1.getRows();
        final RowIterator it2 = adapter2.getRows()
    ) {
      long row = 0L;
      while (it1.moveToNext()) {
        if (!it2.moveToNext()) {
          throw new SegmentValidationException("Unexpected end of second adapter");
        }
        final RowPointer rp1 = it1.getPointer();
        final RowPointer rp2 = it2.getPointer();
        ++row;
        if (rp1.getRowNum() != rp2.getRowNum()) {
          throw new SegmentValidationException("Row number mismatch: [%d] vs [%d]", rp1.getRowNum(), rp2.getRowNum());
        }
        try {

View on GitHub (pinned to 9b90983fd2)