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.
Solutions
- Ensure the upstream materialized view was created with snapshot backfill support before creating the batch refresh MV.
- If batch refresh is not actually needed, create a normal (streaming) MV instead of specifying refresh_interval_sec.
- 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
- Create upstream MVs with snapshot backfill enabled when downstream batch refresh is planned.
- Do not hand-craft create commands omitting snapshot_backfill_info.
- Standardize MV creation through reviewed SQL templates.
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
- batch refresh materialized views must not depend on sources…
- since_timestamp should not be specified when no snapshot…
- Table or source ' ' specified in backfill_order is not used…
- ALTER VIEW SET STREAMING_ENABLE_UNALIGNED_JOIN is not…
- Backfill order strategy has a cycle
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/7313864b2463a7b7.
Report an issue: GitHub.
Appendix: 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)