{"record":{"id":"336143f56240be4d","repo":"apache/druid","slug":"stringfirstaggregator-does-not-support-getlong-336143","errorCode":null,"errorMessage":"StringFirstAggregator does not support getLong()","messagePattern":"StringFirstAggregator does not support getLong\\(\\)","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":121,"sourceCode":"    }\n  }\n\n  @Override\n  public Object get(ByteBuffer buf, int position)\n  {\n    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);","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/firstlast/last/StringLastBufferAggregator.java#L103-L139","documentation":"StringLastBufferAggregator cannot produce a long from its stored timestamp/string pair, so getLong(ByteBuffer,int) throws UnsupportedOperationException. This enforces that string aggregators are consumed through their string result path.","triggerScenarios":"Calling getLong(buf, position) on a StringLastBufferAggregator instance during result collection when the metric is assumed numeric.","commonSituations":"Generic result merge/extraction code in custom extensions; tests that call all three numeric accessors on every buffer aggregator; SQL plans that expect a numeric type but were given stringFirst/stringLast.","solutions":["Extract the value via get(ByteBuffer,int) (the string pair) instead of getLong","Choose a numeric aggregator (longFirst/longLast) when a long is needed","Check AggregatorFactory.getTypeName() and only call the matching typed accessor","Apply SQL CAST(... AS BIGINT) if the string should be interpreted as a long"],"exampleFix":"// before\nlong l = bufAgg.getLong(buf, position); // throws\n// after\nObject val = bufAgg.get(buf, position); // string result\nlong l2 = Long.parseLong((String) val); // only if conversion intended","handlingStrategy":"type-guard","validationCode":"if (\"long\".equals(factory.getTypeName())) { l = bufAgg.getLong(buf, pos); } else { /* string path */ }","typeGuard":"static boolean hasLongAccessor(AggregatorFactory f) { return f.getTypeName().equals(\"long\"); }","tryCatchPattern":"try { l = bufAgg.getLong(buf, pos); } catch (UnsupportedOperationException e) { l = 0L; }","preventionTips":["Check the metric type before integer result extraction","Use longFirst/longLast for integer aggregations","Convert string results explicitly (parseLong) when numeric output is intended"],"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"}