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

  1. Set numberOfValues to metricColumns.size(), or omit numberOfValues so it defaults from metricColumns
  2. Fix the query/ingestion spec JSON so numValues equals the number of entries in metricColumns
  3. 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

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


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)