apache/druid · error · SegmentValidationException

Row number mismatch: [ ] vs [ ]

Error message

Row number mismatch: [%d] vs [%d]

What it means

While walking rows in lockstep, validateTwoSegments checks that corresponding rows have identical row numbers (getRowNum()). This SegmentValidationException is thrown when the two adapters' row pointers diverge in position, meaning row alignment between the segments broke.

Solutions

  1. Inspect the two row numbers in the message to find where alignment diverges.
  2. If a custom adapter is used, fix its row ordering/numbering so rows are yielded in index order with matching rowNum.
  3. Rebuild the suspect segment from source data, then re-validate.
  4. Compare the segments' dimension value ordering (dictionary order affects row layout) if a converter produced them.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  io.validateTwoSegments(adapter1, adapter2);
} catch (SegmentValidationException e) {
  if (e.getMessage().startsWith("Row number mismatch")) {
    log.error("Row alignment broke between adapters: %s", e.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: rp1.getRowNum() != rp2.getRowNum() during the parallel iteration — the second adapter skipped or duplicated a row even though total counts matched.

Common situations: A custom or third-party IndexableAdapter yielding rows out of order; segment rewrite tools reordering rows differently; corrupted dimension dictionaries causing row-pointer misalignment.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/7932427f85d62db6. Report an issue: GitHub.

Appendix: source

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

      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 {
          validateRowValues(rp1, adapter1, rp2, adapter2);
        }
        catch (SegmentValidationException ex) {
          throw new SegmentValidationException(ex, "Validation failure on row %d: [%s] vs [%s]", row, rp1, rp2);
        }
      }
      if (it2.moveToNext()) {
        throw new SegmentValidationException("Unexpected end of first adapter");
      }
      if (row != adapter1.getNumRows()) {
        throw new SegmentValidationException(
            "Actual Row count mismatch. Expected [%d] found [%d]",
            row,
            adapter1.getNumRows()
        );
      }

View on GitHub (pinned to 9b90983fd2)