{"record":{"id":"c22618b5c89a1fea","repo":"apache/druid","slug":"comparing-arrays-of-estimates-and-error-bounds-is-c22618","errorCode":null,"errorMessage":"Comparing arrays of estimates and error bounds is not supported","messagePattern":"Comparing arrays of estimates and error bounds is not supported","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchToEstimateAndBoundsPostAggregator.java","lineNumber":82,"sourceCode":"  }\n\n  @Override\n  public double[] compute(final Map<String, Object> combinedAggregators)\n  {\n    final ArrayOfDoublesSketch sketch = (ArrayOfDoublesSketch) getField().compute(combinedAggregators);\n    return new double[] {sketch.getEstimate(), sketch.getLowerBound(numStdDevs), sketch.getUpperBound(numStdDevs)};\n  }\n\n  @Override\n  public ColumnType getType(ColumnInspector signature)\n  {\n    return ColumnType.DOUBLE_ARRAY;\n  }\n\n  @Override\n  public Comparator<double[]> getComparator()\n  {\n    throw new IAE(\"Comparing arrays of estimates and error bounds is not supported\");\n  }\n\n  @Override\n  public String toString()\n  {\n    return this.getClass().getSimpleName() + \"{\" +\n        \"name='\" + getName() + '\\'' +\n        \", field=\" + getField() +\n        \", numStdDevs=\" + numStdDevs +\n        \"}\";\n  }\n\n  @Override\n  public boolean equals(final Object o)\n  {\n    if (!super.equals(o)) {\n      return false;\n    }","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchToEstimateAndBoundsPostAggregator.java#L64-L100","documentation":"ArrayOfDoublesSketchToEstimateAndBoundsPostAggregator emits a double[] of an estimate plus lower/upper confidence bounds. There is no defined ordering over such arrays, so getComparator() throws IAE unconditionally to reject sorting on this output.","triggerScenarios":"Calling getComparator(), e.g. when the post-aggregator is referenced in an orderBy spec or a sort-enabled query layer iterates post-aggregators for comparators.","commonSituations":"Users sorting results by estimate-and-bounds output; generic tooling assuming every post-aggregator provides a comparator.","solutions":["Use ArrayOfDoublesSketchToEstimatePostAggregator (single double value) if you need a sortable estimate","Sort on a different numeric post-aggregator or metric","Do the ordering client-side after receiving the arrays"],"exampleFix":"// before\nnew ArrayOfDoublesSketchToEstimateAndBoundsPostAggregator(\"eab\", \"sketch\") used in orderBy\n// after\nnew ArrayOfDoublesSketchToEstimatePostAggregator(\"est\", \"sketch\") used in orderBy","handlingStrategy":"try-catch","validationCode":"if (orderByColumns.stream().anyMatch(c -> \"estimateAndBounds\".equals(c.getDimension()))) {\n  throw new IllegalArgumentException(\"Cannot order by estimate-and-bounds array output\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  return queryClient.run(query);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"estimates and error bounds\")) {\n    return runQueryWithAlternateOrdering(query, \"estimate\");\n  }\n  throw e;\n}","preventionTips":["Use the single-value estimate post-aggregator when a sortable value is needed","Keep DOUBLE_ARRAY post-aggregator outputs out of sort specifications","Review generated order-by specs against post-aggregator output types"],"tags":["druid","datasketches","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-17T15:17:12.973Z"}