{"record":{"id":"fdd1cf77192cd91c","repo":"risingwavelabs/risingwave","slug":"the-upstream-fragment-should-be-a-mview-or-source","errorCode":null,"errorMessage":"the upstream fragment should be a MView or Source, got fragment type: {:b}","messagePattern":"the upstream fragment should be a MView or Source, got fragment type: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/stream_graph/fragment.rs","lineNumber":1878,"sourceCode":"                                        \"BUG: column not found in the upstream source node\",\n                                    )?\n                                };\n\n                                StreamFragmentEdge {\n                                    id: EdgeId::UpstreamExternal {\n                                        upstream_job_id,\n                                        downstream_fragment_id: id,\n                                    },\n                                    // We always use `NoShuffle` for the exchange between the upstream\n                                    // `Source` and the downstream `StreamScan` of the new MV.\n                                    dispatch_strategy: DispatchStrategy {\n                                        r#type: DispatcherType::NoShuffle as _,\n                                        dist_key_indices: vec![], // not used for `NoShuffle`\n                                        output_mapping: Some(output_mapping),\n                                    },\n                                }\n                            } else {\n                                bail!(\n                                    \"the upstream fragment should be a MView or Source, got fragment type: {:b}\",\n                                    upstream_fragment.fragment_type_mask\n                                )\n                            }\n                        }\n                        StreamingJobType::Source | StreamingJobType::Table(_) => {\n                            bail!(\n                                \"the streaming job shouldn't have an upstream fragment, job_type: {:?}\",\n                                job_type\n                            )\n                        }\n                    };\n\n                    // put the edge into the extra edges\n                    extra_downstreams\n                        .entry(upstream_root_fragment_id)\n                        .or_insert_with(HashMap::new)\n                        .try_insert(id, edge.clone())","sourceCodeStart":1860,"sourceCodeEnd":1896,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/stream_graph/fragment.rs#L1860-L1896","documentation":"When building the stream graph, downstream edges can only connect to an upstream fragment of type MView (materialized view) or Source without an explicit dispatcher being constructed. If the upstream fragment's type mask is anything else, the builder bails with this error. It prevents connecting a dispatcher-based edge to an upstream fragment that cannot serve as such an upstream.","triggerScenarios":"Creating a streaming job whose external upstream fragment has a fragment type other than MView or Source (e.g. a Table/ materialize fragment or any other mask) while the builder takes the NoShuffle-dispatcher path in graph building.","commonSituations":"Creating a table/sink whose upstream is another table's materialize fragment in a way the planner did not rewrite into a proper MV chain; version changes or planner bugs that leave an unexpected upstream fragment type.","solutions":["Check the SQL: ensure the upstream object is a materialized view or source; create an MV on top of the table if needed and build from that.","Inspect `upstream_fragment.fragment_type_mask` and confirm the intended upstream; if the planner should have rewritten it, check the frontend plan for missing rewriting.","Update RisingWave or file a bug with the DDL statement if a normal MV/Source upstream still triggers this."],"exampleFix":"-- before: CREATE MATERIALIZED VIEW mv2 AS SELECT * FROM base_table;  (upstream is a Table materialize fragment)\n-- after: create an MV over it first\nCREATE MATERIALIZED VIEW mv1 AS SELECT * FROM base_table;\nCREATE MATERIALIZED VIEW mv2 AS SELECT * FROM mv1;","handlingStrategy":"validation","validationCode":"let ok = upstream_fragment.fragment_type_mask == (FragmentTypeMask::MView as u32)\n    || upstream_fragment.fragment_type_mask == (FragmentTypeMask::Source as u32);\nif !ok { return Err(\"upstream must be MView or Source\"); }","typeGuard":"fn is_mview_or_source(mask: u32) -> bool {\n    mask == FragmentTypeMask::MView as u32 || mask == FragmentTypeMask::Source as u32\n}","tryCatchPattern":"match build_stream_graph(job) {\n    Err(e) if e.to_string().contains(\"upstream fragment should be a MView or Source\") => {\n        // fall back: create an MV over the upstream table first\n    }\n    other => other?,\n}","preventionTips":["Build streaming jobs only from materialized views or sources","Create an intermediate MV when the upstream is a table's materialize fragment","Keep planner rewrites that convert table upstreams into MV chains intact"],"tags":["meta","streaming","graph-building"],"backgroundTag":"incompatible-source-type","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"}