risingwavelabs/risingwave · error

batch refresh materialized view must have snapshot backfill

Error message

batch refresh materialized view must have snapshot backfill upstream

What it means

A batch refresh materialized view (refresh_interval_sec specified) must have a snapshot backfill upstream, but snapshot_backfill_info was None. Batch refresh relies on the snapshot backfill machinery to obtain the base data, so without it the job cannot be constructed and the meta node bails.

Source

Thrown at src/meta/src/stream/stream_manager.rs:674

            streaming_job: streaming_job.clone(),
            job_type,
            create_type,
            database_resource_group,
            fragment_backfill_ordering,
            cdc_table_snapshot_splits,
            locality_fragment_state_table_mapping,
            is_serverless: is_serverless_backfill,
            streaming_job_model,
            replace_sink,
            refresh_interval_sec,
        };

        let job_type = if let Some(refresh_interval_sec) = refresh_interval_sec {
            if since_timestamp_epoch.is_some() {
                bail!("since_timestamp should not be specified when no snapshot backfill");
            }
            let snapshot_backfill_info = snapshot_backfill_info.ok_or_else(|| {
                anyhow::anyhow!(
                    "batch refresh materialized view must have snapshot backfill upstream"
                )
            })?;
            // Batch refresh jobs must not contain source or source-backfill nodes,
            // because we skip split assignment resolution for them.
            for fragment in info.stream_job_fragments.inner.fragments.values() {
                let mask = fragment.fragment_type_mask;
                if mask.contains(FragmentTypeFlag::Source)
                    || mask.contains(FragmentTypeFlag::SourceScan)
                {
                    bail!(
                        "batch refresh materialized views must not depend on sources directly; \
                         fragment {} has source/source-backfill nodes",
                        fragment.fragment_id
                    );
                }
            }
            tracing::debug!(

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure the upstream materialized view was created with snapshot backfill support before creating the batch refresh MV.
  2. If batch refresh is not actually needed, create a normal (streaming) MV instead of specifying refresh_interval_sec.
  3. Recreate the upstream MV with the snapshot backfill option, then retry the create.

Example fix

// before: upstream MV created without snapshot backfill, then:
CREATE MATERIALIZED VIEW mv WITH (refresh = '1 hour') AS SELECT * FROM upstream;
-- after: create upstream with snapshot backfill first, or drop refresh option
CREATE MATERIALIZED VIEW upstream WITH (backfill = true) AS ...;
CREATE MATERIALIZED VIEW mv WITH (refresh = '1 hour') AS SELECT * FROM upstream;
Defensive patterns

Strategy: validation

Validate before calling

-- verify upstream supports snapshot backfill before creating a batch refresh MV
SELECT name FROM rw_materialized_views WHERE name = 'upstream' AND properties LIKE '%backfill%';

Try / catch

match result {
    Err(e) if e.to_string().contains("must have snapshot backfill upstream") =>
        return Err("recreate upstream with snapshot backfill first".into()),
    other => other,
}

Prevention

When it happens

Trigger: Creating a streaming job with refresh_interval_sec set while snapshot_backfill_info is None — e.g. the MV's upstream was not created as a snapshot backfill MV, or the info was not propagated through the command.

Common situations: Declaring an interval-refresh MV on a regular table or non-backfill MV; upgrading from a version without snapshot backfill where upstream MVs lack backfill metadata; manually crafting gRPC create commands omitting snapshot_backfill_info.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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