{"record":{"id":"94479aa7c11854c0","repo":"apache/druid","slug":"unknown-object-type-s-94479a","errorCode":null,"errorMessage":"Unknown object type [%s]","messagePattern":"Unknown object type \\[(.+?)\\]","errorType":"exception","errorClass":"org.apache.druid.java.util.common.IAE","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/mean/DoubleMeanAggregatorFactory.java","lineNumber":180,"sourceCode":"  }\n\n  @Override\n  public AggregatorFactory getCombiningFactory()\n  {\n    return new DoubleMeanAggregatorFactory(name, name);\n  }\n\n  @Override\n  public Object deserialize(Object object)\n  {\n    if (object instanceof byte[]) {\n      return DoubleMeanHolder.fromBytes((byte[]) object);\n    } else if (object instanceof String) {\n      return DoubleMeanHolder.fromBytes(StringUtils.decodeBase64(StringUtils.toUtf8((String) object)));\n    } else if (object instanceof DoubleMeanHolder) {\n      return object;\n    } else {\n      throw new IAE(\"Unknown object type [%s]\", Utils.safeObjectClassGetName(object));\n    }\n  }\n\n  @Nullable\n  @Override\n  public Object finalizeComputation(@Nullable Object object)\n  {\n    if (object instanceof byte[]) {\n      return DoubleMeanHolder.fromBytes((byte[]) object).mean();\n    } else if (object instanceof DoubleMeanHolder) {\n      return ((DoubleMeanHolder) object).mean();\n    } else if (object == null) {\n      return null;\n    } else {\n      throw new IAE(\"Unknown object type [%s]\", object.getClass().getName());\n    }\n  }\n","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/mean/DoubleMeanAggregatorFactory.java#L162-L198","documentation":"DoubleMeanAggregatorFactory.deserialize() reconstructs a DoubleMeanHolder from ByteBuffer, byte[], or base64 String (also passing through existing holders). Any other runtime type cannot originate from this aggregator's serialize() and signals a broken intermediate value, so it throws IAE with the value's class name.","triggerScenarios":"Calling deserialize() with a raw Double, Long, Map, or null from segment/cache data not produced by doubleMean serialization — e.g. cache entries from a different aggregator type or hand-built results.","commonSituations":"Druid cache poisoning after changing the metric's aggregator type without clearing caches; cross-version storage format drift; custom code storing the raw finalized double and later trying to deserialize it.","solutions":["Clear the segment result caches (or bump cache identifier/version) after changing aggregator types, then let values be re-populated.","Run the value through finalizeComputation()/deserialize() consistently — only deserialize values produced by DoubleMeanAggregatorFactory.serialize().","Re-ingest or rewrite affected segments so intermediate values are serialized holders.","Wrap raw doubles into a DoubleMeanHolder (or its byte form) before calling deserialize-equivalent paths."],"exampleFix":"// before\nObject holder = factory.deserialize(someDouble);\n// after\nObject holder = (someDouble instanceof Double)\n    ? new DoubleMeanHolder((Double) someDouble, 1L)\n    : factory.deserialize(someDouble);","handlingStrategy":"type-guard","validationCode":"if (object != null && !(object instanceof ByteBuffer) && !(object instanceof byte[]) && !(object instanceof String) && !(object instanceof DoubleMeanHolder)) { throw new IllegalArgumentException(\"Not a serialized DoubleMeanHolder: \" + object.getClass()); }","typeGuard":"boolean isDeserializable(Object o) { return o == null || o instanceof ByteBuffer || o instanceof byte[] || o instanceof String || o instanceof DoubleMeanHolder; }","tryCatchPattern":"try { return factory.deserialize(object); } catch (IllegalArgumentException e) { /* value from wrong aggregator type: re-fetch or re-ingest */ }","preventionTips":["Only deserialize values produced by DoubleMeanAggregatorFactory.serialize().","Invalidate caches when the metric's aggregator type changes.","Verify segment intermediate formats after Druid upgrades.","Guard generic pipelines: confirm factory type before deserialize."],"tags":["druid","aggregation","mean","deserialization","type-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}