{"record":{"id":"1cc0b7a74be619c7","repo":"apache/druid","slug":"both-union-and-sketch-were-null","errorCode":null,"errorMessage":"Both union and sketch were null!","messagePattern":"Both union and sketch were null!","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/HllSketchHolder.java","lineNumber":77,"sourceCode":"\n  public static HllSketchHolder of(HllSketch sketch)\n  {\n    return new HllSketchHolder(null, sketch);\n  }\n\n  private Union union;\n  private HllSketch sketch;\n\n  public HllSketchHolder(\n      Union union,\n      HllSketch sketch\n  )\n  {\n    this.union = union;\n    this.sketch = sketch;\n\n    if (this.union == null && this.sketch == null) {\n      throw new ISE(\"Both union and sketch were null!\");\n    }\n  }\n\n  @JsonValue\n  public HllSketch getSketch()\n  {\n    if (sketch == null) {\n      sketch = union.getResult();\n    }\n\n    return sketch;\n  }\n\n  public HllSketch getSketch(TgtHllType type)\n  {\n    if (sketch == null) {\n      sketch = union.getResult(type);\n    }","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/HllSketchHolder.java#L59-L95","documentation":"The HllSketchHolder constructor stores an optional Union or an optional HllSketch and enforces the invariant that at least one must be non-null. When both are null the holder would represent no sketch at all and every downstream operation would fail, so the constructor throws an IllegalStateException immediately. This is an internal invariant violation, usually caused by calling the constructor directly instead of the static factories.","triggerScenarios":"Invoking new HllSketchHolder(null, null) directly, or a code path where the union was consumed/reduced to null (e.g. after union.reset()) before constructing the holder.","commonSituations":"Custom aggregation code building holders manually; refactoring that nulls out the union field before re-wrapping; copying holders after aggregation finalized the union into a sketch but cleared the reference.","solutions":["Use the static factories HllSketchHolder.of(union) / of(sketch) / of(union, sketch) rather than the raw constructor","If the union was drained, wrap the resulting HllSketch instead of the null union","Add a guard that falls back to a fresh empty Union (new Union(12)) when both inputs would be null"],"exampleFix":"// before\nHllSketchHolder holder = new HllSketchHolder(maybeUnion, null);\n// after\nHllSketchHolder holder = maybeUnion != null ? HllSketchHolder.of(maybeUnion) : HllSketchHolder.of(new Union(12));","handlingStrategy":"validation","validationCode":"if (union == null && sketch == null) { throw new IllegalArgumentException(\"at least one of union/sketch required\"); }","typeGuard":null,"tryCatchPattern":"try { holder = new HllSketchHolder(u, s); } catch (IllegalStateException e) { holder = HllSketchHolder.of(new Union(12)); }","preventionTips":["Always construct holders via HllSketchHolder.of(...) factories","Never null out a union reference before wrapping it","Prefer holding the finalized HllSketch over clearing the union"],"tags":["invariant","datasketches","hll","constructor"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}