{"record":{"id":"2395b4a70b805b3c","repo":"apache/druid","slug":"cannot-have-both-awaitchannels-and-awaitfutures","errorCode":null,"errorMessage":"Cannot have both awaitChannels and awaitFutures","messagePattern":"Cannot have both awaitChannels and awaitFutures","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/processor/ReturnOrAwait.java","lineNumber":74,"sourceCode":"\n  private ReturnOrAwait(\n      @Nullable T retVal,\n      @Nullable IntSet awaitChannels,\n      @Nullable List<ListenableFuture<?>> awaitFutures,\n      final boolean awaitAllChannels\n  )\n  {\n    this.retVal = retVal;\n    this.awaitChannels = awaitChannels;\n    this.awaitAllChannels = awaitAllChannels;\n    this.awaitFutures = awaitFutures;\n\n    if (retVal != null && (awaitChannels != null || awaitFutures != null)) {\n      throw new IAE(\"Cannot have a value when await != null or futures != null\");\n    }\n\n    if (awaitChannels != null && awaitFutures != null) {\n      throw new ISE(\"Cannot have both awaitChannels and awaitFutures\");\n    }\n  }\n\n  /**\n   * Wait for nothing; that is: run again as soon as possible.\n   */\n  public static <T> ReturnOrAwait<T> runAgain()\n  {\n    return new ReturnOrAwait<>(null, IntSets.emptySet(), null, true);\n  }\n\n  /**\n   * Wait for all provided channels to become readable (or finished).\n   *\n   * Numbers in this set correspond to positions in the {@link FrameProcessor#inputChannels()} list.\n   *\n   * It is OK to pass in a mutable set, because this method does not modify the set or retain a reference to it.\n   */","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/processor/ReturnOrAwait.java#L56-L92","documentation":"ReturnOrAwait supports awaiting either channels or futures but not both simultaneously; the constructor throws ISE when awaitChannels and awaitFutures are both non-null. The scheduler would otherwise not know which wait semantics to apply.","triggerScenarios":"Constructing a ReturnOrAwait with both awaitChannels (a Collection of ReadableFrameChannel) and awaitFutures (a Collection of Future) set, typically from a custom processor run() implementation that mixes the two wait styles.","commonSituations":"Custom FrameProcessor code that accumulates channels to await and also defers to async futures in the same step; misusing static factory methods by passing both collections.","solutions":["Await in two steps: first ReturnOrAwait.awaitAll/awaitAny on channels, then a separate ReturnOrAwait.awaitFutures(...) once channels are ready.","Convert one wait kind into the other (e.g. wrap futures as channels or vice versa) so a single await collection is used.","Fix the custom processor's run() to track a single pending-await collection at a time."],"exampleFix":"// before\nreturn new ReturnOrAwait<>(null, channels, null, futures); // ISE\n// after\nif (!channels.isEmpty()) {\n  return ReturnOrAwait.awaitAll(channels);\n}\nreturn ReturnOrAwait.awaitFutures(futures);","handlingStrategy":"validation","validationCode":"if (awaitChannels != null && awaitFutures != null) {\n  throw new IllegalArgumentException(\"Await either channels or futures, not both\");\n}","typeGuard":"boolean singleAwaitMode(Collection<?> channels, Collection<?> futures) { return channels == null || futures == null; }","tryCatchPattern":"try {\n  return ReturnOrAwait.awaitFutures(futures);\n} catch (IllegalStateException e) {\n  // split into sequential awaits\n}","preventionTips":["Never mix channel and future awaits in one step; chain them across run() iterations.","Track a single pending-await collection per processor.","Prefer factory methods over direct construction."],"tags":["java","illegal-state","mutually-exclusive"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}