{"record":{"id":"94309db0a414f483","repo":"apache/druid","slug":"stringfirstaggregator-does-not-support-getdouble-94309d","errorCode":null,"errorMessage":"StringFirstAggregator does not support getDouble()","messagePattern":"StringFirstAggregator 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/StringLastBufferAggregator.java","lineNumber":127,"sourceCode":"    return StringFirstLastUtils.readPair(buf, position);\n  }\n\n  @Override\n  public float getFloat(ByteBuffer buf, int position)\n  {\n    throw new UnsupportedOperationException(\"StringFirstAggregator does not support getFloat()\");\n  }\n\n  @Override\n  public long getLong(ByteBuffer buf, int position)\n  {\n    throw new UnsupportedOperationException(\"StringFirstAggregator does not support getLong()\");\n  }\n\n  @Override\n  public double getDouble(ByteBuffer buf, int position)\n  {\n    throw new UnsupportedOperationException(\"StringFirstAggregator does not support getDouble()\");\n  }\n\n  @Override\n  public void close()\n  {\n    // no resources to cleanup\n  }\n\n  @Override\n  public void inspectRuntimeShape(RuntimeShapeInspector inspector)\n  {\n    inspector.visit(\"timeSelector\", timeSelector);\n    inspector.visit(\"valueSelector\", valueSelector);\n  }\n}\n","sourceCodeStart":109,"sourceCodeEnd":143,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/firstlast/last/StringLastBufferAggregator.java#L109-L143","documentation":"StringLastBufferAggregator's getDouble(ByteBuffer,int) throws UnsupportedOperationException because a last-string aggregator has no double representation. The message mentions StringFirstAggregator because the first/last packages share message strings.","triggerScenarios":"Calling getDouble(buf, position) on a StringLastBufferAggregator when result code assumes all metrics are doubles.","commonSituations":"Custom group-by/topn result formatting that casts everything to double; plugin code migrated from numeric aggregators to string aggregators without updating accessors.","solutions":["Use get(ByteBuffer,int) to read the string value","Switch the metric to doubleLast/double aggregator if a double is required","Dispatch on the factory's type name before calling numeric accessors"],"exampleFix":"// before\ndouble d = bufAgg.getDouble(buf, position); // throws\n// after\nObject v = bufAgg.get(buf, position); // string\ndouble d2 = v == null ? 0.0 : Double.parseDouble((String) v); // only if conversion intended","handlingStrategy":"type-guard","validationCode":"if (\"double\".equals(factory.getTypeName())) { d = bufAgg.getDouble(buf, pos); }","typeGuard":"static boolean hasDoubleAccessor(AggregatorFactory f) { return f.getTypeName().equals(\"double\"); }","tryCatchPattern":"try { d = bufAgg.getDouble(buf, pos); } catch (UnsupportedOperationException e) { d = Double.NaN; }","preventionTips":["Dispatch on factory type name before numeric accessors","Use doubleLast for double-valued last-value metrics","Test custom extraction code against string-typed metrics"],"tags":["java","druid","aggregation","buffer-aggregator","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-14T05:17:10.506Z"}