{"record":{"id":"f1f2f2a3d1920701","repo":"apache/druid","slug":"must-have-at-least-one-element","errorCode":null,"errorMessage":"Must have at least one element","messagePattern":"Must have at least one element","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/processor/TournamentTree.java","lineNumber":81,"sourceCode":"   * Comparator for the elements of the tree.\n   */\n  private final IntComparator comparator;\n\n  /**\n   * Whether this tree has been initialized.\n   */\n  private boolean initialized;\n\n  /**\n   * Creates a tree with a certain number of elements.\n   *\n   * @param numElements number of elements in the tree\n   * @param comparator  comparator for the elements. Smaller elements \"win\".\n   */\n  public TournamentTree(final int numElements, final IntComparator comparator)\n  {\n    if (numElements < 1) {\n      throw new IAE(\"Must have at least one element\");\n    }\n\n    this.numElements = numElements;\n    this.numElementsRounded = HashCommon.nextPowerOfTwo(numElements);\n    this.comparator = comparator;\n    this.tree = new int[numElementsRounded];\n  }\n\n  /**\n   * Get the current minimum element (the overall winner, i.e., the run to pull the next element from in the\n   * K-way merge).\n   */\n  public int getMin()\n  {\n    if (!initialized) {\n      // Defer initialization until the first getMin() call, since the tree object might be created before the\n      // comparator is fully valid. (The comparator is typically not valid until at least one row is available\n      // from each run.)","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/processor/TournamentTree.java#L63-L99","documentation":"TournamentTree is a tournament tree used to merge at least two sorted streams. The constructor requires numElements >= 1; building a tree with zero elements is a programming error because the tree would have no leaves to pop from. IAE signals an invalid argument to the constructor.","triggerScenarios":"Constructing new TournamentTree(0, comparator) — i.e., creating a merge tree over an empty set of channels/batches, such as when a sort/merge pipeline computes zero input channels.","commonSituations":"Empty partition or zero-batch result sets being fed into the frame merge machinery; off-by-one when computing channel counts in custom frame processors.","solutions":["Guard the element count and skip creating a TournamentTree when there are no inputs; return an empty result directly","Ensure the upstream pipeline always yields at least one channel before merging","If the count comes from a computed variable, log/inspect it before construction"],"exampleFix":"// before\nTournamentTree tree = new TournamentTree(channels.size(), comparator);\n// after\nif (channels.isEmpty()) {\n  return Collections.emptyListIterator();\n}\nTournamentTree tree = new TournamentTree(channels.size(), comparator);","handlingStrategy":"validation","validationCode":"if (inputs.size() < 1) { return emptyResult(); }","typeGuard":"boolean canBuildTree(List<?> inputs) { return inputs != null && !inputs.isEmpty(); }","tryCatchPattern":"try { new TournamentTree(n, cmp); } catch (IllegalArgumentException e) { /* handle empty input path */ }","preventionTips":["Check channel/input count before constructing merge structures","Short-circuit empty-input pipelines","Never compute numElements from possibly-empty collections without a guard"],"tags":["sorting","merge","invalid-argument"],"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"}