apache/druid · error · SegmentValidationException
Row count mismatch. Expected
Error message
Row count mismatch. Expected [%d] found [%d]
What it means
IndexIO.validateTwoSegments compares two segment adapters for equivalence. Before comparing rows, it first asserts both adapters report the same numRows; otherwise row-by-row comparison is meaningless. This SegmentValidationException fires when the two segments' row counts differ.
Solutions
- Check the two numbers in the message: determine which segment is missing/extra rows and inspect its input or conversion job logs.
- Re-run ingestion/conversion for the faulty segment after fixing the discrepancy.
- Ensure both segments were built from the same input data and time chunk before validating.
- If validating after a Druid upgrade, confirm row-count-affecting behavior changes (e.g. dedup, rollup settings) match between the two builds.
Defensive patterns
Strategy: validation
Validate before calling
if (adapter1.getNumRows() != adapter2.getNumRows()) {
throw new IllegalStateException("Skip validateTwoSegments: row counts differ: "
+ adapter1.getNumRows() + " vs " + adapter2.getNumRows());
}
io.validateTwoSegments(adapter1, adapter2); Try / catch
try {
io.validateTwoSegments(adapter1, adapter2);
} catch (SegmentValidationException e) {
log.error("Segment validation failed: %s", e.getMessage());
// quarantine the segment, do not publish
} Prevention
- Validate segments only against replicas/rewrites built from identical input.
- Check row counts yourself before invoking row-level comparison for clearer diagnostics.
- Pin ingestion specs (rollup, dimensions) when generating segments intended to be equivalent.
- Re-run validation after any Druid version change that affects segment building.
When it happens
Trigger: Calling IndexIO.validateTwoSegments(adapter1, adapter2) (or the File-based overload) with two segments where adapter1.getNumRows() != adapter2.getNumRows(), typically when validating a converted/rewritten segment against its source.
Common situations: Reindexing or compaction jobs that dropped or duplicated rows; comparing a shard produced by a new Druid version against the original; segment conversion tools (converter/merger) with bugs; comparing segments built from different input slices.
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
- Dimension names differ. Expected
- Metric names differ. Expected
- announceHistoricalSegments failed with null metadata…
- Can't find lock for the interval of segment
- Cannot find a version for interval
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5a046baf5cb8602f.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/IndexIO.java:153
indexLoaders = indexLoadersBuilder.build();
}
public void validateTwoSegments(File dir1, File dir2) throws IOException
{
try (QueryableIndex queryableIndex1 = loadIndex(dir1)) {
try (QueryableIndex queryableIndex2 = loadIndex(dir2)) {
validateTwoSegments(
new QueryableIndexIndexableAdapter(queryableIndex1),
new QueryableIndexIndexableAdapter(queryableIndex2)
);
}
}
}
public void validateTwoSegments(final IndexableAdapter adapter1, final IndexableAdapter adapter2)
{
if (adapter1.getNumRows() != adapter2.getNumRows()) {
throw new SegmentValidationException(
"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)) {View on GitHub (pinned to 9b90983fd2)