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.

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.

Appendix: 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)