apache/druid · error · org.apache.druid.java.util.common.IAE
Number of metricColumns
Error message
Number of metricColumns [%d] must agree with numValues [%d]
What it means
ArrayOfDoublesSketchAggregatorFactory maintains metricColumns (the per-row double columns aggregated) and numberOfValues (how many doubles each sketch row holds). If metricColumns is provided but its size differs from numberOfValues (explicitly set or defaulted), the constructor throws an IAE because the sketch structure would be inconsistent.
Solutions
- Set numberOfValues to metricColumns.size(), or omit numberOfValues so it defaults from metricColumns
- Fix the query/ingestion spec JSON so numValues equals the number of entries in metricColumns
- If metricColumns is irrelevant, pass null for it and specify numberOfValues directly
Example fix
// before
new ArrayOfDoublesSketchAggregatorFactory("agg", "sketch", 16384,
Arrays.asList("m1", "m2", "m3"), 2); // mismatch
// after
new ArrayOfDoublesSketchAggregatorFactory("agg", "sketch", 16384,
Arrays.asList("m1", "m2", "m3"), 3); // or pass null for numberOfValues Defensive patterns
Strategy: validation
Validate before calling
if (metricColumns != null && numberOfValues != null
&& metricColumns.size() != numberOfValues) {
throw new IllegalArgumentException(
"metricColumns size " + metricColumns.size() + " != numValues " + numberOfValues);
} Type guard
boolean isConsistent(List<String> metricColumns, Integer numberOfValues) {
return metricColumns == null || numberOfValues == null
|| metricColumns.size() == numberOfValues;
} Try / catch
try {
ArrayOfDoublesSketchAggregatorFactory f = new ArrayOfDoublesSketchAggregatorFactory(
name, fieldName, nominalEntries, metricColumns, numberOfValues);
} catch (IllegalArgumentException e) {
// fix spec: align numValues with metricColumns size or omit numValues
} Prevention
- Omit numberOfValues and let it default from metricColumns.size()
- When editing ingestion specs, update numValues and metricColumns together
- Validate spec JSON before submission with a schema check
When it happens
Trigger: Constructing new ArrayOfDoublesSketchAggregatorFactory(name, fieldName, nominalEntries, metricColumns, numberOfValues) where metricColumns != null and numberOfValues (explicit or defaulted to metricColumns.size()) conflicts — e.g. metricColumns=[a,b,c] with numberOfValues=2.
Common situations: Hand-written query JSON where 'numValues' doesn't match the length of 'metricColumns'; a stored spec edited to add a metric column without updating numValues; programmatic factory construction passing a stale numberOfValues.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Not implemented
- A-Not-B requires at least 1 sketch
- Can't get sketch from object of type
- Cannot translate sqlTypeName
- Cannot translate sqlTypeName
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/81d97b1b7bef8a6d.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchAggregatorFactory.java:83
@Nullable private final List<String> metricColumns;
@JsonCreator
public ArrayOfDoublesSketchAggregatorFactory(
@JsonProperty("name") final String name,
@JsonProperty("fieldName") final String fieldName,
@JsonProperty("nominalEntries") @Nullable final Integer nominalEntries,
@JsonProperty("metricColumns") @Nullable final List<String> metricColumns,
@JsonProperty("numberOfValues") @Nullable final Integer numberOfValues
)
{
this.name = Preconditions.checkNotNull(name, "Must have a valid, non-null aggregator name");
this.fieldName = Preconditions.checkNotNull(fieldName, "Must have a valid, non-null fieldName");
this.nominalEntries = nominalEntries == null ? ThetaUtil.DEFAULT_NOMINAL_ENTRIES : nominalEntries;
Util.checkIfIntPowerOf2(this.nominalEntries, "nominalEntries");
this.metricColumns = metricColumns;
this.numberOfValues = numberOfValues == null ? (metricColumns == null ? 1 : metricColumns.size()) : numberOfValues;
if (metricColumns != null && metricColumns.size() != this.numberOfValues) {
throw new IAE(
"Number of metricColumns [%d] must agree with numValues [%d]",
metricColumns.size(),
this.numberOfValues
);
}
}
@Override
public Aggregator factorize(final ColumnSelectorFactory metricFactory)
{
if (metricColumns == null) { // input is sketches, use merge aggregator
final BaseObjectColumnValueSelector<ArrayOfDoublesSketch> selector = metricFactory
.makeColumnValueSelector(fieldName);
if (selector instanceof NilColumnValueSelector) {
return new NoopArrayOfDoublesSketchAggregator(numberOfValues);
}
return new ArrayOfDoublesSketchMergeAggregator(selector, nominalEntries, numberOfValues);
}View on GitHub (pinned to 9b90983fd2)