{"record":{"id":"39df7bf597f81569","repo":"apache/druid","slug":"stringfirstaggregator-does-not-support-getdouble-39df7b","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/first/StringFirstBufferAggregator.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/first/StringFirstBufferAggregator.java#L109-L143","documentation":"StringFirstBufferAggregator stores a serialized string pair per group, so getDouble(ByteBuffer,int) is unsupported and always throws UnsupportedOperationException. Reading the buffer cell as a double is invalid by design.","triggerScenarios":"Calling getDouble(buf, position) on a StringFirstBufferAggregator — usually a uniform numeric read path or DOUBLE outputType applied to stringFirst in a buffer-aggregated query.","commonSituations":"Group-by v2 with numeric outputType over stringFirst; shared result-extraction code calling getDouble on every aggregator cell.","solutions":["Read the cell via get(buf, position) instead of getDouble.","Remove DOUBLE outputType or arithmetic post-aggregations on stringFirst.","Use doubleFirst aggregation for numeric earliest values.","Check the aggregator's type before invoking numeric getters."],"exampleFix":"// before\ndouble v = bufAggregator.getDouble(buf, pos);\n// after\nObject v = bufAggregator.get(buf, pos); // SerializablePairLongString","handlingStrategy":"type-guard","validationCode":"if (bufAggregator instanceof StringFirstBufferAggregator) {\n  Object v = bufAggregator.get(buf, position);\n} else {\n  double v = bufAggregator.getDouble(buf, position);\n}","typeGuard":"boolean supportsDouble(BufferAggregator a) {\n  return !(a instanceof StringFirstBufferAggregator);\n}","tryCatchPattern":"try {\n  return agg.getDouble(buf, pos);\n} catch (UnsupportedOperationException e) {\n  Object pair = agg.get(buf, pos);\n  return pair == null ? 0d : Double.parseDouble(String.valueOf(((SerializablePairLongString) pair).rhs));\n}","preventionTips":["Do not declare DOUBLE outputType for stringFirst.","Use doubleFirst for double results.","Extract buffered string cells with get(buf, position)."],"tags":["druid","aggregation","buffer-aggregator","unsupported-getter"],"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"}