risingwavelabs/risingwave · error

upstream table id not covered: {}

Error message

upstream table id not covered: {}

What it means

`fill_snapshot_backfill_epoch` looks up each snapshot-backfill StreamScan's table id in the collected SnapshotBackfillInfo maps (cross-db first, then regular). If the table id appears in neither map, the scan cannot receive a backfill epoch and the function errors, since leaving the epoch unset would produce an invalid graph.

Source

Thrown at src/meta/src/stream/stream_graph/fragment.rs:1622

    let mut applied = false;
    visit_stream_node_cont_mut(node, |node| {
        if let Some(NodeBody::StreamScan(stream_scan)) = node.node_body.as_mut()
            && (stream_scan.stream_scan_type == StreamScanType::SnapshotBackfill as i32
                || stream_scan.stream_scan_type == StreamScanType::CrossDbSnapshotBackfill as i32)
        {
            result = try {
                let table_id = stream_scan.table_id;
                let snapshot_epoch = cross_db_snapshot_backfill_info
                    .upstream_mv_table_id_to_backfill_epoch
                    .get(&table_id)
                    .or_else(|| {
                        snapshot_backfill_info.and_then(|snapshot_backfill_info| {
                            snapshot_backfill_info
                                .upstream_mv_table_id_to_backfill_epoch
                                .get(&table_id)
                        })
                    })
                    .ok_or_else(|| anyhow!("upstream table id not covered: {}", table_id))?
                    .ok_or_else(|| anyhow!("upstream table id not set: {}", table_id))?;
                if let Some(prev_snapshot_epoch) =
                    stream_scan.snapshot_backfill_epoch.replace(snapshot_epoch)
                {
                    Err(anyhow!(
                        "snapshot backfill epoch set again: {} {} {}",
                        table_id,
                        prev_snapshot_epoch,
                        snapshot_epoch
                    ))?;
                }
                applied = true;
            };
            result.is_ok()
        } else {
            true
        }
    });

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure collect_snapshot_backfill_info_impl ran over all fragments containing the scan (fragment_type_mask includes the scan fragments).
  2. Verify the upstream MV's table id didn't change (e.g. after replace) and that maps were built with the same ids.
  3. Recreate the MV chain if the topology was mutated mid-flight, then retry.
Defensive patterns

Strategy: try-catch

Try / catch

// Check coverage before filling:
if !info.upstream_mv_table_id_to_backfill_epoch.contains_key(&table_id) {
    // skip or collect first
}

Prevention

When it happens

Trigger: Filling epochs during replace/refresh where a StreamScan node's table_id is missing from both `cross_db_snapshot_backfill_info` and `snapshot_backfill_info.upstream_mv_table_id_to_backfill_epoch` — e.g. the collect step skipped a fragment or the upstream relation changed id.

Common situations: Schema change or MV refresh where upstream MV topology changed between collect and fill; cross-database scans referencing MVs not registered in the info map; bugs in fragment collection.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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