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

  1. Re-generate both segments from the same source data with identical ingestion specs
  2. Check for missing rows in one segment (dropped data, differing time zones, filters) and re-persist it
  3. 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

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


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