apache/druid · error · org.apache.druid.java.util.common.IAE
lhs[ ] or rhs[ ] not of type [ ]
Error message
lhs[%s] or rhs[%s] not of type [%s]
What it means
DoubleMeanAggregatorFactory.combine() only merges two DoubleMeanHolder instances via update(). If either side is a different type (raw Double, byte[], String, null), the invariant that both inputs are the aggregator's own output type is broken, so it throws an IllegalArgumentException naming the offending classes.
Solutions
- Ensure every input passed to combine() is first run through DoubleMeanAggregatorFactory.deserialize() so byte[]/base64-String forms become DoubleMeanHolder.
- Verify all segments for the metric were ingested with the doubleMean aggregator type; re-ingest mismatched segments.
- Convert raw values yourself: DoubleMeanHolder.fromBytes(...) for byte[], or wrap a double mean/count into a DoubleMeanHolder before combining.
Example fix
// before Object merged = factory.combine(rawA, rawB); // after DoubleMeanAggregatorFactory f = ...; Object merged = f.combine(f.deserialize(rawA), f.deserialize(rawB));
Defensive patterns
Strategy: validation
Validate before calling
if (!(lhs instanceof DoubleMeanHolder) || !(rhs instanceof DoubleMeanHolder)) { throw new IllegalArgumentException("combine inputs must be DoubleMeanHolder; run deserialize() first"); } Type guard
boolean isCombinnable(Object l, Object r) { return l instanceof DoubleMeanHolder && r instanceof DoubleMeanHolder; } Try / catch
try { return factory.combine(lhs, rhs); } catch (IllegalArgumentException e) { return factory.combine(factory.deserialize(lhs), factory.deserialize(rhs)); } Prevention
- Always deserialize intermediate values with the owning AggregatorFactory before combine.
- Keep the same doubleMean aggregator type for a field across all ingestion jobs.
- Clear caches after changing aggregator types.
- Validate partial-result storage format when implementing custom distribution.
When it happens
Trigger: Combine-time (shuffling/merging partial results) where an input value was produced by a different aggregator, deserialized without going through deserialize(), or is null/raw Double from intermediate storage.
Common situations: Mixed aggregator types under the same field name across segments; results combined after skipping intermediate deserialization; custom code feeding raw doubles into the factory's combine instead of holders; cache entries written by an older Druid version using a different intermediate format.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unknown object type [ ]
- Incompatible type for metric
- not supported
- not supported
- StringAnyAggregator does not support getDouble()
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/0f3327d457221cdd.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/mean/DoubleMeanAggregatorFactory.java:155
{
final ColumnCapabilities capabilities = columnInspector.getColumnCapabilities(fieldName);
return capabilities == null || capabilities.isNumeric();
}
@Override
public Comparator getComparator()
{
return DoubleMeanHolder.COMPARATOR;
}
@Nullable
@Override
public Object combine(@Nullable Object lhs, @Nullable Object rhs)
{
if (lhs instanceof DoubleMeanHolder && rhs instanceof DoubleMeanHolder) {
return ((DoubleMeanHolder) lhs).update((DoubleMeanHolder) rhs);
} else {
throw new IAE(
"lhs[%s] or rhs[%s] not of type [%s]",
Utils.safeObjectClassGetName(lhs),
Utils.safeObjectClassGetName(rhs),
DoubleMeanHolder.class.getName()
);
}
}
@Override
public AggregatorFactory getCombiningFactory()
{
return new DoubleMeanAggregatorFactory(name, name);
}
@Override
public Object deserialize(Object object)
{
if (object instanceof byte[]) {View on GitHub (pinned to 9b90983fd2)