risingwavelabs/risingwave · error

source backfill fragment's upstream fragment should have…

Error message

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:?}

What it means

resolve_backfill_splits requires the upstream source fragment to have a one-on-one no_shuffle mapping to the source backfill fragment. This error fires when the entry `actor_no_shuffle[upstream_fragment][fragment]` is entirely absent, meaning the expected 1:1 topology invariant does not hold.

Solutions

  1. Ensure the upstream fragment dispatches with no_shuffle to the backfill fragment
  2. Re-create the MV/source so the planner emits the required 1:1 mapping
  3. Compare the logged actor_no_shuffle map against expected fragment ids
  4. Upgrade RisingWave if the planner violates the source-backfill topology contract
Defensive patterns

Strategy: validation

Validate before calling

// check every backfill fragment has a 1:1 no_shuffle upstream mapping
for (frag, up) in &fragments {
    assert!(actor_no_shuffle.get(up).map_or(false, |m| m.contains_key(frag)));
}

Try / catch

match resolve_backfill_splits(...) {
    Err(e) if e.to_string().contains("one-on-one no_shuffle") => {
        // topology contract broken: recreate the MV/source
    }
    other => other?,
}

Prevention

When it happens

Trigger: Source backfill split resolution where the upstream fragment has no no_shuffle dispatcher record for the backfill fragment id.

Common situations: MV built on a source undergoing backfill with a shuffled (e.g. hash) dispatcher instead of no_shuffle; fragments recreated by ALTER while backfill resolution runs.

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/e4ccc72cd3de8a6d. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/src/stream/source_manager/split_assignment.rs:302

                let upstream_actors: HashSet<ActorId> = actor_no_shuffle
                    .get(&upstream_source_fragment_id)
                    .and_then(|m| m.get(&fragment_id))
                    .ok_or_else(|| {
                        anyhow!(
                            "no upstream actors found from fragment {} to upstream source fragment {}",
                            fragment_id,
                            upstream_source_fragment_id
                        )
                    })?.keys().copied().collect();

                let mut backfill_actors = vec![];
                let Some(source_new_no_shuffle) = actor_no_shuffle
                    .get(&upstream_source_fragment_id)
                    .and_then(|source_upstream_actor_no_shuffle| {
                        source_upstream_actor_no_shuffle.get(&fragment_id)
                    })
                else {
                    return Err(anyhow::anyhow!(
                            "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:?}",
                            fragment_id = fragment_id,
                            upstream_source_fragment_id = upstream_source_fragment_id,
                            actor_no_shuffle = actor_no_shuffle,
                        ).into());
                };
                for upstream_actor in &upstream_actors {
                    let Some(no_shuffle_backfill_actor) = source_new_no_shuffle.get(upstream_actor)
                    else {
                        return Err(anyhow::anyhow!(
                            "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}, upstream_actor: {upstream_actor}, source_new_no_shuffle: {source_new_no_shuffle:?}",
                            fragment_id = fragment_id,
                            upstream_source_fragment_id = upstream_source_fragment_id,
                            upstream_actor = upstream_actor,
                            source_new_no_shuffle = source_new_no_shuffle
                        ).into());
                    };
                    backfill_actors.push((*no_shuffle_backfill_actor, *upstream_actor));

View on GitHub (pinned to 6469eb736d)