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
- Verify hasAwaitableChannels() before calling isAwaitAllChannels()
- Dispatch on the ReturnOrAwait state first (isReturn, hasAwaitableChannels, hasAwaitableFutures) and only read awaitAllChannels in the channels branch
- 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
- Read awaitAllChannels only inside the hasAwaitableChannels() branch
- Structure run loops as an if/else over isReturn/hasAwaitableChannels/hasAwaitableFutures
- Test processors that use both await-all and await-any semantics
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
- No await set
- No futures set
- No value yet
- 08001
- A batch appenderator was already created for this peon's…
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)