apache/druid · error · ParseException

Object cannot be deserialized to a Spectator Histogram

Error message

Object cannot be deserialized to a Spectator Histogram 

What it means

SpectatorHistogram.deserialize expects the incoming object to be a HashMap whose keys are bucket indices and whose values are counts (Numbers). If the serialized object is any other type, the library cannot rebuild a histogram and throws this ParseException. It exists to fail fast on malformed or unexpected payloads rather than silently producing an empty histogram.

Source

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

        HashMap<String, Long> map = JSON_MAPPER.readerFor(HashMap.class).readValue((String) serializedHistogram);
        SpectatorHistogram histogram = new SpectatorHistogram();
        for (Map.Entry<String, Long> entry : map.entrySet()) {
          histogram.add(entry.getKey(), entry.getValue());
        }
        return histogram;
      }
      catch (JsonProcessingException e) {
        throw new ParseException((String) serializedHistogram, e, "String cannot be deserialized as JSON to a Spectator Histogram");
      }
    }
    if (serializedHistogram instanceof HashMap) {
      SpectatorHistogram histogram = new SpectatorHistogram();
      for (Map.Entry<?, ?> entry : ((HashMap<?, ?>) serializedHistogram).entrySet()) {
        histogram.add(entry.getKey(), (Number) entry.getValue());
      }
      return histogram;
    }
    throw new ParseException(
        null,
        "Object cannot be deserialized to a Spectator Histogram "
        + serializedHistogram.getClass()
    );
  }

  @Nullable
  static SpectatorHistogram fromByteBuffer(ByteBuffer buffer)
  {
    if (buffer == null || !buffer.hasRemaining()) {
      return null;
    }
    SpectatorHistogram histogram = new SpectatorHistogram();
    while (buffer.hasRemaining()) {
      short key = buffer.getShort();
      short idx = (short) (key & KEY_MASK);
      long val;
      if ((key & LOW_COUNT_FLAG) == LOW_COUNT_FLAG) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Check that the value passed to deserialize is a HashMap of bucket-index -> count before calling it; reject or log other types upstream.
  2. Verify the serialization side uses SpectatorHistogram.serialize / the matching serde so the payload shape matches.
  3. If ingesting JSON, make sure the column is declared with the spectator histogram sketch type, not a plain numeric column.

Example fix

// before
Object obj = row.get("hist");
SpectatorHistogram h = SpectatorHistogram.deserialize(obj);
// after
if (!(obj instanceof HashMap)) {
  throw new IAE("Expected serialized histogram map, got " + obj.getClass());
}
SpectatorHistogram h = SpectatorHistogram.deserialize(obj);
Defensive patterns

Strategy: type-guard

Validate before calling

if (obj == null || !(obj instanceof HashMap)) {
  throw new IAE("Cannot deserialize " + (obj == null ? "null" : obj.getClass()) + " as SpectatorHistogram");
}

Type guard

boolean isSerializedHistogram(Object o) {
  return o instanceof HashMap;
}

Try / catch

try {
  SpectatorHistogram h = SpectatorHistogram.deserialize(obj);
} catch (ParseException e) {
  log.warn(e, "Bad histogram payload: %s", obj == null ? "null" : obj.getClass());
  h = new SpectatorHistogram();
}

Prevention

When it happens

Trigger: Calling SpectatorHistogram.deserialize(Object) with a value that is not a HashMap — e.g. a plain Number, String, List, or a custom map type produced by a different serializer version.

Common situations: A Druid segment or query payload was serialized by an older/newer serializer that wraps histograms differently; a user hand-crafted JSON for a post-aggregator where the histogram is a scalar; deserializing a field that was never actually a SpectatorHistogram (column type confusion).

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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