apache/druid · error · SegmentValidationException
Dimension names differ. Expected
Error message
Dimension names differ. Expected [%s] found [%s]
What it means
During two-segment validation, IndexIO compares the sets of dimension names of both adapters. This SegmentValidationException is thrown when the dimension name sets differ, meaning one segment has dimensions the other lacks (or vice versa).
Solutions
- Diff the two dimension sets printed in the message to find the added/missing dimensions.
- Align ingestion specs (dimensionsList vs auto-discovery) so both segments carry the same schema.
- If the extra dimension is unintended, remove it from the input or spec and rebuild the segment.
- If dimensions were intentionally renamed, the segments are legitimately different — validate against the correct reference segment instead.
Example fix
// before: mismatched specs
spec1: {"dimensionsSpec":{"dimensions":["page","user"]}}
spec2: {"dimensionsSpec":{"dimensions":["page"]}}
// after: identical schemas
spec1: {"dimensionsSpec":{"dimensions":["page","user"]}}
spec2: {"dimensionsSpec":{"dimensions":["page","user"]}} Defensive patterns
Strategy: validation
Validate before calling
Set<String> dims1 = Sets.newHashSet(adapter1.getDimensionNames(true));
Set<String> dims2 = Sets.newHashSet(adapter2.getDimensionNames(true));
if (!dims1.equals(dims2)) {
System.out.println("Dim diff: only-1=" + Sets.difference(dims1, dims2)
+ " only-2=" + Sets.difference(dims2, dims1));
} Try / catch
try {
io.validateTwoSegments(adapter1, adapter2);
} catch (SegmentValidationException e) {
if (e.getMessage().startsWith("Dimension names differ")) {
log.error("Schema drift detected between segments: %s", e.getMessage());
}
throw e;
} Prevention
- Use explicit dimension lists in ingestion specs instead of schema auto-discovery when exact schema parity matters.
- Verify specs are identical before building segments meant to be validated against each other.
- Track schema drift in streaming ingestion (Kafka/Kinesis) with schema registry checks.
- Document intentional dimension renames so validators compare the correct reference segment.
When it happens
Trigger: validateTwoSegments with segments whose getDimensionNames(true) sets are unequal — e.g. one segment has an extra or missing dimension column.
Common situations: Schema drift between ingestion batches; auto-discovery of dimensions adding a field in only one segment; comparing a segment before/after a transform or dimension-exclusion change; upgrading with changed schema handling.
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
- Metric names differ. Expected
- Row count mismatch. Expected
- Aggregation [ ] does not support column [ ] of type [ ]…
- An inline input source must provide one or more columns
- announceHistoricalSegments failed with null metadata…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/2910a46fec151e73.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/IndexIO.java:163
);
}
}
}
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)) {
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()) {View on GitHub (pinned to 9b90983fd2)