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
- Inspect the two row numbers in the message to find where alignment diverges.
- If a custom adapter is used, fix its row ordering/numbering so rows are yielded in index order with matching rowNum.
- Rebuild the suspect segment from source data, then re-validate.
- 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
- Ensure custom IndexableAdapter implementations yield rows in strict index order with correct rowNum.
- Do not reorder rows when rewriting segments intended for equivalence validation.
- Test custom adapters against validateTwoSegments with a known-good segment.
- Rebuild segments from source when row-order inconsistencies appear.
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
- Dim [ ] values not equal. Expected found
- Dimension names differ. Expected
- Metric names differ. Expected
- Row count mismatch. Expected
- Unexpected end of first adapter
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)