{"record":{"id":"5ac0b633cad26327","repo":"apache/druid","slug":"stringfirstaggregator-does-not-support-getlong","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/first/StringFirstAggregator.java","lineNumber":101,"sourceCode":"    }\n  }\n\n  @Override\n  public Object get()\n  {\n    return new SerializablePairLongString(firstTime, StringUtils.chop(firstValue, maxStringBytes));\n  }\n\n  @Override\n  public float getFloat()\n  {\n    throw new UnsupportedOperationException(\"StringFirstAggregator does not support getFloat()\");\n  }\n\n  @Override\n  public long getLong()\n  {\n    throw new UnsupportedOperationException(\"StringFirstAggregator does not support getLong()\");\n  }\n\n  @Override\n  public double getDouble()\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","sourceCodeStart":83,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/firstlast/first/StringFirstAggregator.java#L83-L116","documentation":"StringFirstAggregator produces a string result (earliest value with its timestamp), so getLong() is unsupported and always throws UnsupportedOperationException. Numeric extraction from a string-first aggregate is invalid by design.","triggerScenarios":"Calling getLong() on StringFirstAggregator — e.g. a post-aggregation or finalizer that assumes a long output, or a numeric outputType configured for stringFirst.","commonSituations":"Misconfigured native query with outputType Long on a stringFirst aggregator; custom code reading aggregator values via getLong; SQL planner mismatch producing a long-typed expression over stringFirst.","solutions":["Read the value as a string/object via the aggregator's get() method instead of getLong().","Remove or correct the outputType/post-aggregator that declares a long result for stringFirst.","Use LongFirstAggregator (type \"longFirst\") if the earliest numeric value is desired.","Cast/parse explicitly at the SQL layer only after retrieving the string, if a numeric interpretation is truly needed."],"exampleFix":"// before\n{\"type\":\"stringFirst\",\"name\":\"s\",\"fieldName\":\"col\",\"outputType\":\"LONG\"}\n// after\n{\"type\":\"stringFirst\",\"name\":\"s\",\"fieldName\":\"col\"}","handlingStrategy":"type-guard","validationCode":"if (aggregator instanceof StringFirstAggregator) {\n  Object v = aggregator.get();\n} else {\n  long v = aggregator.getLong();\n}","typeGuard":"boolean supportsLong(Aggregator a) {\n  return !(a instanceof StringFirstAggregator);\n}","tryCatchPattern":"try {\n  return agg.getLong();\n} catch (UnsupportedOperationException e) {\n  Object pair = agg.get();\n  return pair == null ? 0L : Long.parseLong(String.valueOf(((SerializablePairLongString) pair).rhs));\n}","preventionTips":["Set outputType correctly (string) for stringFirst.","Use longFirst for numeric earliest values.","Avoid generic numeric getter loops over heterogeneous aggregators."],"tags":["druid","aggregation","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"}