apache/druid · error · IllegalStateException
Broadcast input number out of range
Error message
Broadcast input number out of range [%s]
What it means
During StageDefinition construction, each broadcast input number must be a valid index into the stage's inputSpecs map (0 <= n < inputSpecs.size()). Out-of-range values mean the stage graph references an input channel that does not exist, so ISE("Broadcast input number out of range [%s]") is thrown.
Solutions
- Renumber broadcast inputs so each is a 0-based index into the stage's inputSpecs
- Verify the stage actually has as many input specs as the highest broadcast number + 1
- If inputs were removed, rebuild the stage definition instead of mutating broadcast numbers
Example fix
// before builder.broadcastInputNumbers(ImmutableIntList.of(2)); // stage has 2 inputs (0..1) // after builder.broadcastInputNumbers(ImmutableIntList.of(1));
Defensive patterns
Strategy: validation
Validate before calling
for (int n : broadcastInputNumbers) {
if (n < 0 || n >= inputSpecs.size()) {
throw new IllegalStateException("Broadcast input out of range: " + n);
}
} Try / catch
try { StageDefinition def = builder.build(); } catch (IllegalStateException e) { log.error("Stage graph error: {}", e.getMessage()); } Prevention
- Renumber broadcast inputs whenever input specs are added or removed
- Build stage graphs programmatically rather than hard-coding input numbers
- Add a stage-graph consistency test covering broadcast inputs
When it happens
Trigger: Building a StageDefinition with broadcastInputNumbers containing a negative value or an index >= number of input specs — e.g. declaring broadcastInput(3) on a stage with only 2 inputs, or reusing a broadcast number from a differently-shaped stage graph.
Common situations: Hand-assembling MSQ controller/worker stage graphs in tests or tooling, or planner bugs after removing stages/inputs without renumbering broadcast references.
Related errors
- Can not supply empty segments as input, please use either…
- Cannot have empty worker set
- Cannot have fault tolerance without durable storage
- Cannot mix sortable and unsortable key columns
- Cannot shuffle with spec
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/8c0ecd72019f4fb5.
Report an issue: GitHub.
Appendix: source
Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/kernel/StageDefinition.java:149
this.signature = Preconditions.checkNotNull(signature, "signature");
this.shuffleSpec = shuffleSpec;
this.maxWorkerCount = maxWorkerCount;
this.shuffleCheckHasMultipleValues = shuffleCheckHasMultipleValues;
this.frameReader = Suppliers.memoize(() -> FrameReader.create(signature))::get;
if (mustGatherResultKeyStatistics() && shuffleSpec.clusterBy().isEmpty()) {
throw new IAE("Cannot shuffle with spec [%s] and nil clusterBy", shuffleSpec);
}
for (final String columnName : signature.getColumnNames()) {
if (!signature.getColumnType(columnName).isPresent()) {
throw new ISE("Missing type for column [%s]", columnName);
}
}
for (final int broadcastInputNumber : this.broadcastInputNumbers) {
if (broadcastInputNumber < 0 || broadcastInputNumber >= inputSpecs.size()) {
throw new ISE("Broadcast input number out of range [%s]", broadcastInputNumber);
}
}
}
public static boolean mustGatherResultKeyStatistics(@Nullable final ShuffleSpec shuffleSpec)
{
return shuffleSpec != null
&& shuffleSpec.kind() == ShuffleKind.GLOBAL_SORT
&& ((GlobalSortShuffleSpec) shuffleSpec).mustGatherResultKeyStatistics();
}
public static StageDefinitionBuilder builder(final int stageNumber)
{
return new StageDefinitionBuilder(stageNumber);
}
public static StageDefinitionBuilder builder(final StageDefinition stageDef)
{View on GitHub (pinned to 9b90983fd2)