{"record":{"id":"370be97dba34e568","repo":"risingwavelabs/risingwave","slug":"the-stage-has-single-distribution-but-contains-a","errorCode":null,"errorMessage":"The stage has single distribution, but contains a source operator","messagePattern":"The stage has single distribution, but contains a source operator","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/frontend/src/scheduler/plan_fragmenter.rs","lineNumber":1082,"sourceCode":"                            tracing::warn!(\n                                \"The stage has single distribution, but contains a scan of table `{}` with {} partitions. A single random worker will be assigned\",\n                                info.name,\n                                partitions.len()\n                            );\n\n                            *partitions = partitions\n                                .drain()\n                                .take(1)\n                                .update(|(_, info)| {\n                                    info.vnode_bitmap = Bitmap::ones(info.vnode_bitmap.len());\n                                })\n                                .collect();\n                        }\n                    } else {\n                        // System table\n                    }\n                } else if source_info.is_some() {\n                    return Err(SchedulerError::Internal(anyhow!(\n                        \"The stage has single distribution, but contains a source operator\"\n                    )));\n                }\n                1\n            }\n            _ => {\n                if let Some(table_scan_info) = &table_scan_info {\n                    table_scan_info\n                        .partitions\n                        .as_ref()\n                        .map(|m| m.len())\n                        .unwrap_or(1)\n                } else if let Some(lookup_join_parallelism) =\n                    self.collect_stage_lookup_join_parallelism(root.clone())?\n                {\n                    has_lookup_join = true;\n                    lookup_join_parallelism\n                } else if source_info.is_some() {","sourceCodeStart":1064,"sourceCodeEnd":1100,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/scheduler/plan_fragmenter.rs#L1064-L1100","documentation":"Raised while computing distribution/parallelism in the plan fragmenter (src/frontend/src/scheduler/plan_fragmenter.rs:1082): a stage whose plan has single (1-way) distribution was found to contain a source operator. Source operators require partitioned scheduling with splits, which contradicts the single-distribution assumption, so the invariant is broken.","triggerScenarios":"Fragmenting a batch plan where the optimizer emitted a single-distribution stage containing a source scan node — e.g. a source scan under an operator that forces single distribution (like certain aggregation or limit plans) without the expected exchange insertion.","commonSituations":"Internal planner/optimizer inconsistencies after plan-shape changes; queries with sources combined under single-distribution-forcing operators.","solutions":["Inspect `EXPLAIN (TRACE)` to find the source operator inside a single-distribution stage.","Rewrite the query to avoid the pattern (e.g. add explicit ordering/limiting steps) as a workaround.","Fix the optimizer rule so an exchange is inserted between a single-distribution consumer and a source scan.","Report with the query and plan if it occurs on a stock workload."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match fragmenter_result {\n    Err(e) if e.to_string().contains(\"single distribution, but contains a source operator\") => {\n        log::error!(\"plan invariant broken: source under single-distribution stage; check EXPLAIN (TRACE)\");\n    }\n    r => r?,\n}","preventionTips":["Inspect EXPLAIN (TRACE) for source scans under single-distribution operators.","Keep optimizer exchange-insertion rules tested.","Avoid exotic query shapes mixing sources with single-distribution operators until fixed upstream."],"tags":["scheduler","plan-fragmenter","distribution","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"}