{"record":{"id":"7baacbb2cbd587a1","repo":"risingwavelabs/risingwave","slug":"row-sequential-scan-should-not-have-input-executor","errorCode":null,"errorMessage":"Row sequential scan should not have input executor!","messagePattern":"Row sequential scan should not have input executor!","errorType":"validation","errorClass":"BatchError","httpStatus":null,"severity":"error","filePath":"src/batch/executors/src/executor/row_seq_scan.rs","lineNumber":90,"sourceCode":"            identity,\n            metrics,\n            table,\n            scan_ranges,\n            ordered,\n            query_epoch,\n            limit,\n        }\n    }\n}\n\npub struct RowSeqScanExecutorBuilder {}\n\nimpl BoxedExecutorBuilder for RowSeqScanExecutorBuilder {\n    async fn new_boxed_executor(\n        source: &ExecutorBuilder<'_>,\n        inputs: Vec<BoxedExecutor>,\n    ) -> Result<BoxedExecutor> {\n        ensure!(\n            inputs.is_empty(),\n            \"Row sequential scan should not have input executor!\"\n        );\n        let seq_scan_node = try_match_expand!(\n            source.plan_node().get_node_body().unwrap(),\n            NodeBody::RowSeqScan\n        )?;\n\n        let table_desc: &StorageTableDesc = seq_scan_node.get_table_desc()?;\n        let column_ids = seq_scan_node\n            .column_ids\n            .iter()\n            .copied()\n            .map(ColumnId::from)\n            .collect();\n        let vnodes = match &seq_scan_node.vnode_bitmap {\n            Some(vnodes) => Some(Bitmap::from(vnodes).into()),\n            // This is possible for dml. vnode_bitmap is not filled by scheduler.","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/batch/executors/src/executor/row_seq_scan.rs#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (planner builds scan with a child)\nBatchPlanNode::new(RowSeqScan { table_ref }, vec![child])\n// after (leaf node, no children)\nBatchPlanNode::new(RowSeqScan { table_ref }, vec![])","handlingStrategy":"try-catch","validationCode":"// Rust (planner code): assert leaf arity before building\nassert!(children.is_empty(), \"RowSeqScan must be a leaf node\");","typeGuard":"fn is_leaf(inputs: &[BoxedExecutor]) -> bool { inputs.is_empty() }","tryCatchPattern":"match exec.build(plan_node).await {\n    Ok(exec) => exec,\n    Err(e) if e.to_string().contains(\"should not have input executor\") => {\n        // log plan tree and report internal invariant violation\n        e.to_string()\n    }\n}","preventionTips":["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."],"tags":["batch-executor","planner","rust","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}