risingwavelabs/risingwave · error · BatchError
Source should not have input executor!
Error message
Source should not have input executor!
What it means
SourceExecutor's BoxedExecutorBuilder requires the Source executor to be a leaf with zero child executors. A source executor reads rows from an external connector (Kafka, etc.) or from a table, so it must never receive child executors from the plan. Receiving one indicates the plan tree was built incorrectly.
Source
Thrown at src/batch/executors/src/executor/source.rs:58
// used to create reader
column_ids: Vec<ColumnId>,
metrics: Arc<SourceMetrics>,
source_id: SourceId,
split_list: Vec<SplitImpl>,
schema: Schema,
identity: String,
chunk_size: usize,
}
impl BoxedExecutorBuilder for SourceExecutor {
async fn new_boxed_executor(
source: &ExecutorBuilder<'_>,
inputs: Vec<BoxedExecutor>,
) -> Result<BoxedExecutor> {
ensure!(inputs.is_empty(), "Source should not have input executor!");
let source_node = try_match_expand!(
source.plan_node().get_node_body().unwrap(),
NodeBody::Source
)?;
// prepare connector source
let options_with_secret = WithOptionsSecResolved::new(
source_node.with_properties.clone(),
source_node.secret_refs.clone(),
);
let config = ConnectorProperties::extract(options_with_secret.clone(), false)
.map_err(BatchError::connector)?;
let info = source_node.get_info().unwrap();
let parser_config = SpecificParserConfig::new(info, &options_with_secret)?;
let columns: Vec<_> = source_node
.columnsView on GitHub (pinned to 6469eb736d)
Solutions
- Verify the plan tree: the Source node must be a leaf; remove any child edges produced by the planner.
- Fix the frontend/batch planner code so Source nodes are built with an empty children list.
- When constructing SourceExecutor in tests, pass an empty inputs vector to the builder.
- File an internal bug with the failing query if the planner output seems correct.
Example fix
// before let node = BatchPlanNode::new(NodeBody::Source(source_node), vec![child]); // after let node = BatchPlanNode::new(NodeBody::Source(source_node), vec![]);
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: validate before building the source executor assert!(inputs.is_empty(), "Source node must have no children");
Type guard
fn has_no_children(inputs: &[BoxedExecutor]) -> bool { inputs.is_empty() } Try / catch
if let Err(e) = builder.new_boxed_executor(&src, inputs).await {
if e.to_string().contains("Source should not have input executor") {
// dump plan tree for debugging
}
} Prevention
- Ensure Source plan nodes are always constructed as leaves.
- Test frontend-to-batch plan translation for source nodes.
- Never wire child executors under connector source scans.
When it happens
Trigger: new_boxed_executor is called with a non-empty `inputs` vec because a Source plan node in the batch plan has children attached.
Common situations: Planner bugs that attach a child under a Source/scan node; hand-built plan trees in tests or internal tooling that wire executors under a source; refactors of plan-node arity rules.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Row sequential scan should not have input executor!
- Row sequential scan should not have input executor!
- ValuesExecutor should have no child!
- VectorIndexNearest should have an input executor!
- GenerateSeriesExecutor should not have child!
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9049ffd1497c84c7.
Report an issue: GitHub.