risingwavelabs/risingwave · error · BatchError
Row sequential scan should not have input executor!
Error message
Row sequential scan should not have input executor!
What it means
RowSeqScanExecutorBuilder::new_boxed_executor asserts that the row sequential scan executor is built with zero child executors. A row seq scan is a leaf node in the batch query plan that reads rows directly from a table, so the executor framework must hand it no inputs. Receiving an input means the planner wired a child under a leaf node, which is an internal invariant violation, not a user-facing error.
Source
Thrown at src/batch/executors/src/executor/row_seq_scan.rs:90
identity,
metrics,
table,
scan_ranges,
ordered,
query_epoch,
limit,
}
}
}
pub struct RowSeqScanExecutorBuilder {}
impl BoxedExecutorBuilder for RowSeqScanExecutorBuilder {
async fn new_boxed_executor(
source: &ExecutorBuilder<'_>,
inputs: Vec<BoxedExecutor>,
) -> Result<BoxedExecutor> {
ensure!(
inputs.is_empty(),
"Row sequential scan should not have input executor!"
);
let seq_scan_node = try_match_expand!(
source.plan_node().get_node_body().unwrap(),
NodeBody::RowSeqScan
)?;
let table_desc: &StorageTableDesc = seq_scan_node.get_table_desc()?;
let column_ids = seq_scan_node
.column_ids
.iter()
.copied()
.map(ColumnId::from)
.collect();
let vnodes = match &seq_scan_node.vnode_bitmap {
Some(vnodes) => Some(Bitmap::from(vnodes).into()),
// This is possible for dml. vnode_bitmap is not filled by scheduler.View on GitHub (pinned to 6469eb736d)
Solutions
- Inspect the generated plan (EXPLAIN / plan debug output) and confirm the RowSeqScan node has no children; if it does, fix the planner code that builds it.
- Check that the frontend translates RowSeqScan into a leaf batch plan node with arity 0.
- If you are adding executors manually, ensure RowSeqScanExecutor is passed an empty inputs vec when calling the builder.
- Report as an internal bug with the query that triggered it if the planner looks correct.
Example fix
// before (planner builds scan with a child)
BatchPlanNode::new(RowSeqScan { table_ref }, vec![child])
// after (leaf node, no children)
BatchPlanNode::new(RowSeqScan { table_ref }, vec![]) Defensive patterns
Strategy: try-catch
Validate before calling
// Rust (planner code): assert leaf arity before building assert!(children.is_empty(), "RowSeqScan must be a leaf node");
Type guard
fn is_leaf(inputs: &[BoxedExecutor]) -> bool { inputs.is_empty() } Try / catch
match exec.build(plan_node).await {
Ok(exec) => exec,
Err(e) if e.to_string().contains("should not have input executor") => {
// log plan tree and report internal invariant violation
e.to_string()
}
} Prevention
- Keep leaf plan nodes (RowSeqScan) with empty children lists in the planner.
- Add unit tests asserting plan-node arity after planning.
- Use EXPLAIN to inspect plans when touching executor builders.
When it happens
Trigger: The batch executor builder framework dispatches to RowSeqScanExecutorBuilder with a non-empty `inputs` vector, i.e. the plan tree contains a RowSeqScan plan node that has children.
Common situations: A bug in the frontend/batch planner that attaches a child to a RowSeqScan node; manual construction of a plan fragment that feeds an executor into a seq scan; internal refactors that changed executor arity conventions.
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
- Source 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/7baacbb2cbd587a1.
Report an issue: GitHub.