apache/druid · error · java.lang.UnsupportedOperationException
StringFirstAggregator does not support getDouble()
Error message
StringFirstAggregator does not support getDouble()
What it means
Sentinel guard in the string-first aggregator's typed read API: this aggregator's result is a SerializablePairLongString (timestamp + string value), which has no double representation, so getDouble() is intentionally unsupported. It fires when a query plan binds a string-first first/last aggregation output to a DOUBLE-typed read; use getFloat()/getLong()-free object access (via the pair) or an aggregation whose output matches the requested primitive type.
Source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/firstlast/first/StringFirstAggregator.java:107
return new SerializablePairLongString(firstTime, StringUtils.chop(firstValue, maxStringBytes));
}
@Override
public float getFloat()
{
throw new UnsupportedOperationException("StringFirstAggregator does not support getFloat()");
}
@Override
public long getLong()
{
throw new UnsupportedOperationException("StringFirstAggregator does not support getLong()");
}
@Override
public double getDouble()
{
throw new UnsupportedOperationException("StringFirstAggregator does not support getDouble()");
}
@Override
public void close()
{
// no resources to cleanup
}
}
View on GitHub (pinned to 9b90983fd2)
Solutions
- Use the aggregator's object/string getter to read the value.
- Drop the DOUBLE outputType or arithmetic post-aggregator applied to stringFirst output.
- Use DoubleFirstAggregator (type "doubleFirst") when an earliest numeric double is needed.
- Guard access by checking the aggregator type before invoking getDouble().
Example fix
// before double d = aggregator.getDouble(); // after Object pair = aggregator.get(); // SerializablePairLongString String s = pair == null ? null : ((SerializablePairLongString) pair).rhs;
Defensive patterns
Strategy: type-guard
Validate before calling
if (aggregator instanceof StringFirstAggregator) {
Object v = aggregator.get();
} else {
double v = aggregator.getDouble();
} Type guard
boolean supportsDouble(Aggregator a) {
return !(a instanceof StringFirstAggregator);
} Try / catch
try {
return agg.getDouble();
} catch (UnsupportedOperationException e) {
Object pair = agg.get();
return pair == null ? 0d : Double.parseDouble(String.valueOf(((SerializablePairLongString) pair).rhs));
} Prevention
- Use doubleFirst instead of stringFirst when doubles are expected.
- Avoid arithmetic post-aggregators directly over stringFirst output.
- Check aggregator types before numeric extraction.
When it happens
Trigger: Calling getDouble() on StringFirstAggregator, usually from a post-aggregator, finalizer, or generic numeric accessor treating the aggregate as a double.
Common situations: Using stringFirst inside arithmetic post-aggregations; configuring a DOUBLE outputType for stringFirst; shared aggregator-reading code paths that call all numeric getters.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- StringFirstAggregator does not support getFloat()
- StringFirstAggregator does not support getLong()
- StringFirstAggregator does not support getFloat()
- StringFirstAggregator does not support getLong()
- StringFirstAggregator does not support getDouble()
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/cd8398edff90b19a.
Report an issue: GitHub.