apache/druid · error · SegmentValidationException
Actual Row count mismatch. Expected [%d] found [%d]
Error message
Actual Row count mismatch. Expected [%d] found [%d]
What it means
IndexIO.validateRowValues compares rows at the same pointer position when validating two segments against each other. If the row counts differ (or the pointer walks past one segment before the other), it reports an actual/expected row-count mismatch. This indicates the two segments do not contain identical row data and cannot be considered equivalent.
Source
Thrown at processing/src/main/java/org/apache/druid/segment/IndexIO.java:249
if (fileSize > Integer.MAX_VALUE) {
throw new IOE("File[%s] too large[%d]", indexFile, fileSize);
}
}
interface IndexIOHandler
{
MMappedIndex mapDir(File inDir) throws IOException;
}
private static void validateRowValues(
RowPointer rp1,
IndexableAdapter adapter1,
RowPointer rp2,
IndexableAdapter adapter2
)
{
if (rp1.getTimestamp() != rp2.getTimestamp()) {
throw new SegmentValidationException(
"Timestamp mismatch. Expected %d found %d",
rp1.getTimestamp(),
rp2.getTimestamp()
);
}
final List<Object> dims1 = rp1.getDimensionValuesForDebug();
final List<Object> dims2 = rp2.getDimensionValuesForDebug();
if (dims1.size() != dims2.size()) {
throw new SegmentValidationException("Dim lengths not equal %s vs %s", dims1, dims2);
}
final List<String> dim1Names = adapter1.getDimensionNames(false);
final List<String> dim2Names = adapter2.getDimensionNames(false);
int dimCount = dims1.size();
for (int i = 0; i < dimCount; ++i) {
final String dim1Name = dim1Names.get(i);
final String dim2Name = dim2Names.get(i);
ColumnCapabilities capabilities1 = adapter1.getCapabilities(dim1Name);View on GitHub (pinned to 9b90983fd2)
Solutions
- Re-generate both segments from the same source data with identical ingestion specs
- Check for missing rows in one segment (dropped data, differing time zones, filters) and re-persist it
- Verify both segments use the same interval and rollup settings before validating
Defensive patterns
Strategy: validation
Validate before calling
try (IndexableAdapter a1 = IndexIO.loadAdapter(seg1); IndexableAdapter a2 = IndexIO.loadAdapter(seg2)) {
if (a1.getNumRows() != a2.getNumRows()) {
throw new IllegalStateException("Row counts differ: " + a1.getNumRows() + " vs " + a2.getNumRows());
}
} Try / catch
try {
IndexIO.validateTwoSegments(adapter1, adapter2);
} catch (SegmentValidationException e) {
log.error("Segments not equivalent: %s", e.getMessage());
// treat as invalid comparison, re-generate source segment
} Prevention
- Only validate segments generated from identical inputs and specs
- Verify row counts match before deep row-by-row validation
When it happens
Trigger: Calling IndexIO.validateTwoSegments (or the validation utility wrapping it) on two segment files where the number of rows in one differs from the other, producing mismatched RowPointer iterations.
Common situations: Post-merge or post-conversion verification of segments that were re-ingested with different filters or time zones; comparing a migrated segment against its source; validation tooling run against partially-written segments.
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
- Dim lengths not equal %s vs %s
- Dim [%s] types not equal. Expected %d found %d
- Aggregation [%s] does not support column [%s] of type [%s].
- Cannot accept both 'splitPoints' and 'numBins'
- at least 2 bins expected
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/0ff1560ea2be13d8.
Report an issue: GitHub.