{"record":{"id":"0f0d1be92c09649f","repo":"apache/druid","slug":"stringlastaggregator-does-not-support-getdouble","errorCode":null,"errorMessage":"StringLastAggregator does not support getDouble()","messagePattern":"StringLastAggregator does not support getDouble\\(\\)","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/firstlast/last/StringLastAggregator.java","lineNumber":107,"sourceCode":"    return new SerializablePairLongString(lastTime, StringUtils.chop(lastValue, maxStringBytes));\n  }\n\n  @Override\n  public float getFloat()\n  {\n    throw new UnsupportedOperationException(\"StringLastAggregator does not support getFloat()\");\n  }\n\n  @Override\n  public long getLong()\n  {\n    throw new UnsupportedOperationException(\"StringLastAggregator does not support getLong()\");\n  }\n\n  @Override\n  public double getDouble()\n  {\n    throw new UnsupportedOperationException(\"StringLastAggregator does not support getDouble()\");\n  }\n\n  @Override\n  public void close()\n  {\n    // no resources to cleanup\n  }\n}\n","sourceCodeStart":89,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/firstlast/last/StringLastAggregator.java#L89-L116","documentation":"StringLastAggregator stores the last observed string value (pair of timestamp + string) and cannot yield a double. getDouble() is required by the Aggregator interface but is intentionally unimplemented, throwing UnsupportedOperationException to surface type misuse early.","triggerScenarios":"Calling getDouble() on a StringLastAggregator instance, e.g. when query result extraction assumes numeric metrics or when a vectorized/non-vectorized code path blindly calls getDouble for all metrics.","commonSituations":"Building custom Druid extensions or result formats that read all aggregators as doubles; misconfiguring a metric as string-last but consuming it as a numeric in a dashboard or post-aggregator.","solutions":["Read the string value via the aggregator's string/get() result path instead of getDouble()","Switch to a numeric aggregator (doubleLast) when a double result is required","Dispatch on AggregatorFactory.getTypeName() before calling numeric accessors","CAST the string metric to DOUBLE in SQL if numeric conversion is intended"],"exampleFix":"// before\ndouble d = agg.getDouble(); // throws\n// after\nif (\"double\".equals(factory.getTypeName())) {\n  double d = agg.getDouble();\n} else {\n  Object s = agg.get();\n}","handlingStrategy":"type-guard","validationCode":"if (\"string\".equals(factory.getTypeName())) { /* read string value via agg.get() */ }","typeGuard":"static boolean isNumericAggregator(AggregatorFactory f) { return f.getTypeName().matches(\"long|float|double\"); }","tryCatchPattern":"try { d = agg.getDouble(); } catch (UnsupportedOperationException e) { d = Double.NaN; }","preventionTips":["Match metric type to consumer expectations at query-spec construction time","Use doubleLast/double aggregators when doubles are needed downstream","Add unit tests that assert accessor compatibility per aggregator type"],"tags":["java","druid","aggregation","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}