apache/druid · error · IllegalStateException

No channels set

Error message

No channels set

What it means

isAwaitAllChannels() reports whether the processor wants ALL channels in awaitableChannels() satisfied (vs any), but it is only defined when the object is in the AWAIT_CHANNELS state. If there is no channel set (RETURN or AWAIT_FUTURES state), an ISE with 'No channels set' is thrown. Like the other ReturnOrAwait accessors, it guards variant misuse of this union type.

Solutions

  1. Verify hasAwaitableChannels() before calling isAwaitAllChannels()
  2. Dispatch on the ReturnOrAwait state first (isReturn, hasAwaitableChannels, hasAwaitableFutures) and only read awaitAllChannels in the channels branch
  3. Make the processor return ReturnOrAwait.await(channels, awaitAllChannels) so the flag is populated when channels are awaited

Example fix

// before
boolean all = outcome.isAwaitAllChannels();
// after
if (outcome.hasAwaitableChannels()) {
  boolean all = outcome.isAwaitAllChannels();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (outcome.hasAwaitableChannels()) { allChannels = outcome.isAwaitAllChannels(); }

Type guard

boolean hasChannelConfig(ReturnOrAwait<?> o) { return o != null && o.hasAwaitableChannels(); }

Try / catch

try { all = outcome.isAwaitAllChannels(); } catch (IllegalStateException e) { if (!e.getMessage().contains("No channels set")) throw e; /* not a channel await */ }

Prevention

When it happens

Trigger: The run loop calls isAwaitAllChannels() on an outcome that has no awaitable channels — e.g. after isAwait() returns true it skips the hasAwaitableChannels() check, or the outcome came from awaitFutures(...)/returnOrNull(...).

Common situations: Scheduler code that assumes every await outcome is a channel-await and reads awaitAllChannels for the waitAny/waitAll decision; processors that switched from channel-based to future-based awaiting but the runner wasn't updated.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/c14db19415861dc5. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/frame/processor/ReturnOrAwait.java:217

    return awaitFutures != null;
  }

  /**
   * Whether the processor wants to wait for a set of channels. If true, {@link #awaitableChannels()} contains the
   * set of channels to wait for, and {@link #isAwaitAllChannels()}.
   */
  public boolean hasAwaitableChannels()
  {
    return awaitChannels != null;
  }

  /**
   * Whether the processor wants to wait for all channels in {@link #awaitableChannels()} (true), or any channel (false)
   */
  public boolean isAwaitAllChannels()
  {
    if (!hasAwaitableChannels()) {
      throw new ISE("No channels set");
    }

    return awaitAllChannels;
  }

  @Override
  public String toString()
  {
    if (hasAwaitableChannels()) {
      return "await channels=" + (awaitAllChannels ? "all" : "any") + awaitChannels;
    } else if (hasAwaitableFutures()) {
      return "await futures=" + awaitFutures;
    } else {
      return "return=" + retVal;
    }
  }

  private static IntSet rangeSet(final int count)

View on GitHub (pinned to 9b90983fd2)