{"record":{"id":"b79cacc4aadbab71","repo":"apache/druid","slug":"cannot-compare-against-something-that-is-not-a-tom","errorCode":null,"errorMessage":"Cannot compare against something that is not a TombstonePartitionedChunk.","messagePattern":"Cannot compare against something that is not a TombstonePartitionedChunk\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/timeline/partition/TombstonePartitionedChunk.java","lineNumber":74,"sourceCode":"  @Override\n  public boolean isEnd()\n  {\n    return true;\n  }\n\n  @Override\n  public int getChunkNumber()\n  {\n    return 0;\n  }\n\n  @Override\n  public int compareTo(PartitionChunk<T> other)\n  {\n    if (other instanceof TombstonePartitionedChunk) {\n      return 0;\n    } else {\n      throw new IllegalArgumentException(\"Cannot compare against something that is not a TombstonePartitionedChunk.\");\n    }\n  }\n\n  @Override\n  @SuppressWarnings(\"unchecked\")\n  public boolean equals(Object o)\n  {\n    if (this == o) {\n      return true;\n    }\n    if (o == null || getClass() != o.getClass()) {\n      return false;\n    }\n\n    return compareTo((TombstonePartitionedChunk<T>) o) == 0;\n  }\n\n  @Override","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/timeline/partition/TombstonePartitionedChunk.java#L56-L92","documentation":"TombstonePartitionedChunk.compareTo returns 0 only when the other chunk is also a TombstonePartitionedChunk; comparing against any other PartitionChunk implementation throws this IllegalArgumentException. Tombstones are equal/ordering-neutral to each other, so cross-type comparison is intentionally unsupported rather than defined.","triggerScenarios":"Calling compareTo or equals on a TombstonePartitionedChunk with a non-tombstone PartitionChunk, e.g. a StringPartitionChunk, typically during timeline chunk sorting or equality checks in segment-drop/replacement code.","commonSituations":"Segment replacement flows where tombstone chunks and normal chunks end up in the same sorted collection; code iterating a PartitionHolder mixing tombstone and data chunks; tests comparing tombstone chunks to data chunks.","solutions":["Separate tombstone chunks from regular partition chunks before sorting or comparing them","Guard comparisons with instanceof TombstonePartitionedChunk checks before calling compareTo","Adjust the calling merge/sort logic to treat tombstones as a distinct category instead of relying on Comparable","If a total order over mixed chunks is needed, wrap chunks in a comparator that handles cross types explicitly"],"exampleFix":"// before\nchunks.sort(Comparator.naturalOrder()); // mixed types throw\n// after\nchunks.sort((a, b) -> {\n  if (a instanceof TombstonePartitionedChunk && b instanceof TombstonePartitionedChunk) return 0;\n  if (a instanceof TombstonePartitionedChunk) return -1;\n  if (b instanceof TombstonePartitionedChunk) return 1;\n  return a.compareTo(b);\n});","handlingStrategy":"type-guard","validationCode":"if (!(other instanceof TombstonePartitionedChunk)) {\n  // handle non-tombstone comparison separately\n}","typeGuard":"static <T> boolean isTombstoneChunk(PartitionChunk<T> c) {\n  return c instanceof TombstonePartitionedChunk;\n}","tryCatchPattern":"try {\n  cmp = tombstoneChunk.compareTo(other);\n} catch (IllegalArgumentException e) {\n  // treat as cross-type: define explicit ordering\n}","preventionTips":["Sort tombstones separately from data chunks","Use a comparator that handles mixed chunk types explicitly","Avoid relying on equals across chunk implementations"],"tags":["java","illegal-argument","comparison","tombstones"],"backgroundTag":"invalid-argument-value","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"}