apache/druid · error · IllegalArgumentException

at least 2 bins expected

Error message

at least 2 bins expected

What it means

At compute time the histogram post-aggregator resolves the effective bin count (splitPoints.length + 1, numBins, or the default) and requires at least 2 bins — a histogram with 0 or 1 bins is meaningless. It throws IAE when the resolved count is below 2.

Source

Thrown at extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregator.java:73

      @JsonProperty("numBins") @Nullable final Integer numBins)
  {
    this.name = Preconditions.checkNotNull(name, "name is null");
    this.field = Preconditions.checkNotNull(field, "field is null");
    this.splitPoints = splitPoints;
    this.numBins = numBins;
    if (splitPoints != null && numBins != null) {
      throw new IAE("Cannot accept both 'splitPoints' and 'numBins'");
    }
  }

  @Override
  public Object compute(final Map<String, Object> combinedAggregators)
  {
    final KllFloatsSketch sketch = (KllFloatsSketch) field.compute(combinedAggregators);
    final int numBins = this.splitPoints != null ? this.splitPoints.length + 1 :
        (this.numBins != null ? this.numBins.intValue() : DEFAULT_NUM_BINS);
    if (numBins < 2) {
      throw new IAE("at least 2 bins expected");
    }
    if (sketch.isEmpty()) {
      final double[] histogram = new double[numBins];
      Arrays.fill(histogram, Double.NaN);
      return histogram;
    }
    final float[] splitPoints;
    if (this.splitPoints != null) {
      splitPoints = this.splitPoints;
    } else {
      final float min = sketch.getMinItem();
      final float max = sketch.getMaxItem();
      if (min == max) {
        // if min is equal to max, we can't create an array of equally spaced points.
        // all values would go into the first bucket anyway, and the remaining
        // buckets are left as zero.
        final double[] histogram = new double[numBins];
        histogram[0] = sketch.getN();

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Set numBins to at least 2 in the post-aggregator spec.
  2. If using splitPoints, provide at least one split point (yielding 2 bins); pass null rather than an empty array if you want the default binning.
  3. Clamp or validate the bin count in the calling code before building the query.

Example fix

// before
int numBins = userBins; // could be 1

// after
int numBins = Math.max(2, userBins);
Defensive patterns

Strategy: validation

Validate before calling

int numBins = splitPoints != null ? splitPoints.length + 1 : (numBinsOpt != null ? numBinsOpt : 10);
if (numBins < 2) throw new IllegalArgumentException("numBins must be >= 2");

Prevention

When it happens

Trigger: Passing numBins <= 1, or supplying an empty splitPoints array (length 0, resolving to 1 bin). Note numBins=0/null falls back to the default and is fine; only numBins=1 or empty splitPoints trigger this.

Common situations: Dynamic query builders that compute numBins from user input or a formula that can evaluate to 1, or passing an empty array for splitPoints instead of null.

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/7b366f961e583df1. Report an issue: GitHub.