{"record":{"id":"dada0747e0851537","repo":"risingwavelabs/risingwave","slug":"no-upstream-actors-found-from-fragment-to-upstr","errorCode":null,"errorMessage":"no upstream actors found from fragment {} to upstream source fragment {}","messagePattern":"no upstream actors found from fragment (.+?) to upstream source fragment (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/source_manager/split_assignment.rs","lineNumber":288,"sourceCode":"    /// with its upstream source fragment using the `new_no_shuffle` actor mapping and\n    /// the existing split assignment looked up via the provided closure.\n    pub fn resolve_backfill_splits(\n        table_fragments: &StreamJobFragments,\n        actor_no_shuffle: &ActorNewNoShuffle,\n        get_upstream_actor_splits: impl Fn(FragmentId, ActorId) -> Option<Vec<SplitImpl>>,\n    ) -> MetaResult<SplitAssignment> {\n        let source_backfill_fragments = table_fragments.source_backfill_fragments();\n\n        let mut assigned = HashMap::new();\n\n        for (_source_id, fragments) in source_backfill_fragments {\n            for (fragment_id, upstream_source_fragment_id) in fragments {\n                // Get upstream actors from actor_no_shuffle mapping\n                let upstream_actors: HashSet<ActorId> = actor_no_shuffle\n                    .get(&upstream_source_fragment_id)\n                    .and_then(|m| m.get(&fragment_id))\n                    .ok_or_else(|| {\n                        anyhow!(\n                            \"no upstream actors found from fragment {} to upstream source fragment {}\",\n                            fragment_id,\n                            upstream_source_fragment_id\n                        )\n                    })?.keys().copied().collect();\n\n                let mut backfill_actors = vec![];\n                let Some(source_new_no_shuffle) = actor_no_shuffle\n                    .get(&upstream_source_fragment_id)\n                    .and_then(|source_upstream_actor_no_shuffle| {\n                        source_upstream_actor_no_shuffle.get(&fragment_id)\n                    })\n                else {\n                    return Err(anyhow::anyhow!(\n                            \"source backfill fragment's upstream fragment should have one-on-one no_shuffle mapping, fragment_id: {fragment_id}, upstream_fragment_id: {upstream_source_fragment_id}, actor_no_shuffle: {actor_no_shuffle:?}\",\n                            fragment_id = fragment_id,\n                            upstream_source_fragment_id = upstream_source_fragment_id,\n                            actor_no_shuffle = actor_no_shuffle,","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/source_manager/split_assignment.rs#L270-L306","documentation":"resolve_backfill_splits builds the upstream actor set for a source backfill fragment from the `actor_no_shuffle` mapping; this error fires when the (upstream_fragment -> fragment) entry has no actor map. A one-on-one no-shuffle mapping is mandatory for source backfill topologies.","triggerScenarios":"Calling resolve_backfill_splits (during source backfill split resolution/migration) when the upstream source fragment lacks a no_shuffle actor mapping to the backfill fragment, e.g. the upstream dispatches with a non-no_shuffle dispatcher.","commonSituations":"Source backfill created against an upstream plan that does not guarantee 1:1 no-shuffle distribution; topology changes after MV rebuild; version mismatch between frontend planner and meta assumptions.","solutions":["Check the upstream fragment uses no_shuffle dispatch to the backfill fragment","Recreate the source/backfill so the plan is regenerated with the expected topology","Inspect actor_no_shuffle in meta logs to see which edge is missing","Report/upgrade if the planner produced a non-no-shuffle edge for source backfill"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before resolving backfill splits, confirm the upstream fragment has no_shuffle dispatchers\nassert!(actor_no_shuffle.contains_key(&upstream_source_fragment_id));","typeGuard":null,"tryCatchPattern":"if let Err(e) = resolve_backfill_splits(...) {\n    tracing::error!(\"backfill topology invalid: {e}\");\n    // recreate the MV/source instead of retrying\n}","preventionTips":["Only build source backfill on plans with 1:1 no_shuffle dispatch","Keep frontend and meta on the same version","Verify dispatcher types in fragment metadata when debugging backfill"],"tags":["rust","meta","source-backfill","split-assignment"],"backgroundTag":"record-not-found","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}