{"record":{"id":"003784f9530a2de9","repo":"apache/druid","slug":"s-does-not-implement-makeaggregatecombiner","errorCode":null,"errorMessage":"[%s] does not implement makeAggregateCombiner()","messagePattern":"\\[(.+?)\\] does not implement makeAggregateCombiner\\(\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/AggregatorFactory.java","lineNumber":130,"sourceCode":"   * @param rhs The right hand side of the combine\n   *\n   * @return an object representing the combination of lhs and rhs, this can be a new object or a mutation of the inputs\n   */\n  @Nullable\n  public abstract Object combine(@Nullable Object lhs, @Nullable Object rhs);\n\n  /**\n   * Creates an AggregateCombiner to fold rollup aggregation results from serveral \"rows\" of different indexes during\n   * index merging. AggregateCombiner implements the same logic as {@link #combine}, with the difference that it uses\n   * {@link org.apache.druid.segment.ColumnValueSelector} and it's subinterfaces to get inputs and implements {@code\n   * ColumnValueSelector} to provide output.\n   *\n   * @see AggregateCombiner\n   * @see org.apache.druid.segment.IndexMerger\n   */\n  public AggregateCombiner makeAggregateCombiner()\n  {\n    throw new UOE(\"[%s] does not implement makeAggregateCombiner()\", this.getClass().getName());\n  }\n\n  /**\n   * Creates an {@link AggregateCombiner} which supports nullability.\n   * Implementations of {@link AggregatorFactory} which need to Support Nullable Aggregations are encouraged\n   * to extend {@link NullableNumericAggregatorFactory} instead of overriding this method.\n   * Default implementation calls {@link #makeAggregateCombiner()} for backwards compatibility.\n   *\n   * @see AggregateCombiner\n   * @see NullableNumericAggregatorFactory\n   */\n  public AggregateCombiner makeNullableAggregateCombiner()\n  {\n    return makeAggregateCombiner();\n  }\n\n  /**\n   * Returns an AggregatorFactory that can be used to combine the output of aggregators from this factory. It is used","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/AggregatorFactory.java#L112-L148","documentation":"AggregatorFactory.makeAggregateCombiner() is an abstract-style hook that must return an AggregateCombiner used when merging pre-aggregated segments (e.g. during IndexMerger merges). The base class throws this UOE to signal that the concrete aggregator factory does not support combining-based merging, so an attempt to merge segments containing this aggregator cannot proceed.","triggerScenarios":"Calling makeAggregateCombiner() (directly or via combiner()/makeNullableAggregateCombiner()) on an AggregatorFactory subclass that has not overridden the method, then using it in segment merging or nullable aggregation paths.","commonSituations":"Custom aggregator implementations missing the override; using an aggregator type in a rollup/merge context that only supports incremental aggregation; version changes where combining support became required for a code path.","solutions":["Override makeAggregateCombiner() in your AggregatorFactory subclass to return a proper AggregateCombiner for your aggregator","If supporting nullable aggregations, extend NullableNumericAggregatorFactory instead of implementing the method directly","Use an aggregator type that supports combining (implements getCombiningFactory/makeAggregateCombiner) in merge scenarios"],"exampleFix":"// before\npublic class MyAggregatorFactory extends AggregatorFactory {\n  // no makeAggregateCombiner override\n}\n// after\npublic class MyAggregatorFactory extends AggregatorFactory {\n  @Override\n  public AggregateCombiner makeAggregateCombiner() {\n    return new MyAggregateCombiner();\n  }\n}","handlingStrategy":"type-guard","validationCode":"// before merging\nif (!(factory instanceof AggregatorFactory) || factory.getClass().equals(AggregatorFactory.class)) {\n  throw new IllegalStateException(\"Aggregator must override makeAggregateCombiner()\");\n}","typeGuard":"boolean supportsCombining(AggregatorFactory f) {\n  try { f.makeAggregateCombiner(); return true; } catch (UnsupportedOperationException e) { return false; }\n}","tryCatchPattern":"try {\n  combiner = factory.makeAggregateCombiner();\n} catch (UnsupportedOperationException e) {\n  log.error(\"Aggregator %s cannot merge segments\", factory.getClass(), e);\n  throw new QueryInterruptedException(\"aggregator-not-mergeable\");\n}","preventionTips":["Always override makeAggregateCombiner in custom AggregatorFactory subclasses","Prefer extending NullableNumericAggregatorFactory for nullable numeric aggregators","Test custom aggregators with segment merging (rollup) scenarios before production"],"tags":["aggregation","merge","druid"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}