{"record":{"id":"edc335d8707272d4","repo":"apache/druid","slug":"not-decorated","errorCode":null,"errorMessage":"Not decorated","messagePattern":"Not decorated","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/post/FinalizingFieldAccessPostAggregator.java","lineNumber":86,"sourceCode":"  {\n    this.name = name;\n    this.fieldName = fieldName;\n    this.finalizedType = finalizedType;\n    this.comparator = comparator;\n    this.finalizer = finalizer;\n  }\n\n  @Override\n  public Set<String> getDependentFields()\n  {\n    return Sets.newHashSet(fieldName);\n  }\n\n  @Override\n  public Comparator getComparator()\n  {\n    if (comparator == null) {\n      throw new UnsupportedOperationException(\"Not decorated\");\n    } else {\n      return comparator;\n    }\n  }\n\n  @Override\n  public Object compute(Map<String, Object> combinedAggregators)\n  {\n    if (finalizer == null) {\n      throw new UnsupportedOperationException(\"Not decorated\");\n    } else {\n      return finalizer.apply(combinedAggregators.get(fieldName));\n    }\n  }\n\n  @Override\n  @JsonProperty\n  public String getName()","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/post/FinalizingFieldAccessPostAggregator.java#L68-L104","documentation":"FinalizingFieldAccessPostAggregator.getComparator throws UnsupportedOperationException(\"Not decorated\") when the aggregator has not been wrapped by the finalization decorator that installs the comparator. This class is a shell: its comparator/finalizer fields are populated by decorate(...), and direct use of the undecorated instance is a programming error.","triggerScenarios":"Calling getComparator() on a FinalizingFieldAccessPostAggregator that was never passed through AggregatorFactory's finalization/decoration step, or on one whose delegate produced a null comparator.","commonSituations":"Unit tests instantiating the post-aggregator directly without decorating it; custom query code building post-aggregators manually and skipping the decoration phase of query processing.","solutions":["Run the post-aggregator through the normal query decoration/finalization pipeline so decorate(...) installs the comparator","If decorating manually, call decorate(...) with the appropriate input before invoking getComparator()","Use the factory's finalizeComputation path instead of accessing the raw comparator of an undecorated instance"],"exampleFix":"// before\nComparator c = new FinalizingFieldAccessPostAggregator(\"x\", \"agg\").getComparator();\n// after\nPostAggregator decorated = new FinalizingFieldAccessPostAggregator(\"x\", \"agg\")\n    .decorate(Collections.singletonList(aggregatorFactory));\nComparator c = decorated.getComparator();","handlingStrategy":"validation","validationCode":"if (postAgg instanceof FinalizingFieldAccessPostAggregator && !isDecorated(postAgg)) {\n  throw new IllegalStateException(\"decorate() before getComparator()\");\n}","typeGuard":"boolean isDecorated(FinalizingFieldAccessPostAggregator p) { try { p.getComparator(); return true; } catch (UnsupportedOperationException e) { return false; } }","tryCatchPattern":"try { c = postAgg.getComparator(); } catch (UnsupportedOperationException e) { c = defaultComparatorForField(fieldName); }","preventionTips":["Always let the query engine's decoration phase wrap post-aggregators","In tests, call decorate(...) with real AggregatorFactories before asserting","Never call getComparator/compute on raw FinalizingFieldAccessPostAggregator instances"],"tags":["java","post-aggregator","unsupported-operation"],"backgroundTag":"method-not-implemented","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"}