apache/druid · error · IllegalArgumentException

Expected a Number, but received [%s] of type [%s]

Error message

Expected a Number, but received [%s] of type [%s]

What it means

SpectatorHistogramAggregateHelper.merge combines the aggregator's current histogram with either another SpectatorHistogram or a single Number sample. Any other object type is unsupported and throws IAE naming the received value and its class. It is the helper's type contract for what can be folded into the aggregation.

Source

Thrown at extensions-contrib/spectator-histogram/src/main/java/org/apache/druid/spectator/histogram/SpectatorHistogramAggregateHelper.java:53

  public void init(ByteBuffer buffer, int position)
  {
    SpectatorHistogram emptyCounts = new SpectatorHistogram();
    addToCache(buffer, position, emptyCounts);
  }

  /**
   * Merge obj ({@link SpectatorHistogram} or {@link Number}) into {@param current}.
   */
  public void merge(SpectatorHistogram current, Object obj)
  {
    if (obj instanceof SpectatorHistogram) {
      SpectatorHistogram other = (SpectatorHistogram) obj;
      current.merge(other);
    } else if (obj instanceof Number) {
      current.insert((Number) obj);
    } else {
      throw new IAE(
          "Expected a Number, but received [%s] of type [%s]",
          obj,
          obj.getClass()
      );
    }
  }

  /**
   * Merge {@param value} into {@param current}.
   */
  public void merge(SpectatorHistogram current, long value)
  {
    current.insert(value);
  }

  /**
   * Fetches the SpectatorHistogram at the given buffer/position pair in the cache
   */

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Verify the input column is numeric or of the spectator-histogram sketch type before aggregating.
  2. Cast or convert the object to Number / SpectatorHistogram before calling merge, or reject the row upstream.
  3. Check for serialization mismatches between writer and reader versions of the extension.

Example fix

// before
helper.merge(current, row.getRaw("metric")); // may be a String
// after
Object v = row.getRaw("metric");
if (v instanceof SpectatorHistogram || v instanceof Number) {
  helper.merge(current, v);
} else {
  throw new IAE("Unsupported metric type: " + v.getClass());
}
Defensive patterns

Strategy: validation

Validate before calling

static boolean isMergeable(Object o) {
  return o instanceof SpectatorHistogram || o instanceof Number;
}

Type guard

static boolean isHistogramOrNumber(Object o) {
  return o instanceof SpectatorHistogram || o instanceof Number;
}

Try / catch

try {
  helper.merge(current, obj);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Expected a Number")) {
    log.warn("Skipping non-numeric input of type %s", obj.getClass());
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A column or post-aggregator input yields a non-numeric, non-histogram object (e.g. String, Map, null-wrapped complex value) and the helper's merge(obj) is invoked on it during aggregation.

Common situations: Pointing the aggregator at a column of the wrong type (strings/dimensions instead of numeric metrics or histogram sketches); a serializer delivering a different sketch class; upstream filters or transforms emitting complex objects into the metric slot.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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