{"record":{"id":"2d75207d9e71c3cb","repo":"apache/druid","slug":"cannot-have-a-value-when-await-null-or-futures","errorCode":null,"errorMessage":"Cannot have a value when await != null or futures != null","messagePattern":"Cannot have a value when await != null or futures != null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/processor/ReturnOrAwait.java","lineNumber":70,"sourceCode":"  private final boolean awaitAllChannels;\n\n  @Nullable\n  private final List<ListenableFuture<?>> awaitFutures;\n\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   *","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/processor/ReturnOrAwait.java#L52-L88","documentation":"ReturnOrAwait is a sum type for FrameProcessor.run() results: either a return value OR a set of channels/futures to await, never both. Its constructor enforces this mutual exclusivity with IAE when retVal is non-null while awaitChannels or awaitFutures is also non-null. This keeps processor scheduling unambiguous.","triggerScenarios":"Building ReturnOrAwait via a factory or constructor with both a return value and await inputs, e.g. `ReturnOrAwait.value(x)` after also setting await fields, or custom code calling the (private/package) constructor with mixed parameters.","commonSituations":"Custom FrameProcessor implementations that accidentally return both a result and a pending await; misusing static factories like awaitAll/awaitAny together with a value.","solutions":["Return exactly one mode: use ReturnOrAwait.value(...) for a result, or awaitChannels/awaitFutures factories for waiting, not both.","In a custom processor, return the await object while work is pending and only produce a value when nothing is left to await.","Review the processor's run() to ensure each return path sets either retVal or await fields, never both."],"exampleFix":"// before\nreturn new ReturnOrAwait<>(result, channels, null, null); // IAE\n// after\nreturn channels.isEmpty() ? ReturnOrAwait.value(result) : ReturnOrAwait.awaitAll(channels);","handlingStrategy":"validation","validationCode":"if (retVal != null && (awaitChannels != null || awaitFutures != null)) {\n  throw new IllegalArgumentException(\"ReturnOrAwait cannot carry both a value and await inputs\");\n}","typeGuard":"boolean wellFormed(ReturnOrAwait<?> r) { return r != null; } // build only via value()/await*() factories","tryCatchPattern":"try {\n  return ReturnOrAwait.value(result);\n} catch (IllegalArgumentException e) {\n  // fall back to await path\n}","preventionTips":["Only construct ReturnOrAwait via its static factories (value, awaitAll, awaitAny, awaitFutures).","In run(), return await objects while pending work exists and values only when done.","Keep each return path single-mode."],"tags":["java","argument-validation","mutually-exclusive"],"backgroundTag":"mutually-exclusive-options","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"}