risingwavelabs/risingwave · error · anyhow::Error
recovered snapshot backfill job {} has no snapshot backfill
Error message
recovered snapshot backfill job {} has no snapshot backfill info What it means
Same invariant as the batch-refresh variant but on the recovery path of `inject_database_initial_barrier`: a snapshot backfill job being recovered must expose snapshot backfill info derived from its persisted fragments; when the lookup returns None the recovery aborts with this error. It indicates the recovered job's fragment metadata lacks the expected snapshot backfill node.
Source
Thrown at src/meta/src/barrier/rpc.rs:825
);
if committed_epoch == barrier_info.prev_epoch() {
info!(
"recovered creating snapshot backfill job {} catch up with upstream already",
job_id
);
database_jobs
.try_insert(job_id, (fragment_infos, true))
.expect("non-duplicate");
continue;
}
let snapshot_backfill_info = StreamFragmentGraph::collect_snapshot_backfill_info_impl(
fragment_infos
.values()
.map(|fragment| (&fragment.nodes, fragment.fragment_type_mask)),
)?
.0
.ok_or_else(|| {
anyhow!(
"recovered snapshot backfill job {} has no snapshot backfill info",
job_id
)
})?;
let mut snapshot_epoch = None;
let upstream_table_ids: HashSet<_> = snapshot_backfill_info
.upstream_mv_table_id_to_backfill_epoch
.keys()
.cloned()
.collect();
for (upstream_table_id, epoch) in
snapshot_backfill_info.upstream_mv_table_id_to_backfill_epoch
{
let epoch = epoch.ok_or_else(|| anyhow!("recovered snapshot backfill job {} to upstream {} has not set snapshot epoch", job_id, upstream_table_id))?;
let snapshot_epoch = snapshot_epoch.get_or_insert(epoch);
if *snapshot_epoch != epoch {
return Err(anyhow!("snapshot epoch {} to upstream {} different to snapshot epoch {} to previous upstream", epoch, upstream_table_id, snapshot_epoch).into());
}View on GitHub (pinned to 6469eb736d)
Solutions
- Dump the job's fragment infos from the meta store and verify a snapshot backfill fragment exists.
- Restore meta state from a consistent snapshot/backup if recovery state is corrupted.
- Upgrade consistently: ensure all persisted jobs were created by a version that persists snapshot backfill info.
- If unrecoverable, drop and recreate the affected job.
Defensive patterns
Strategy: validation
Validate before calling
// On recovery, pre-check persisted fragment infos before injecting the barrier
if !fragment_infos.values().any(|f| {
f.nodes.values().any(|n| n.snapshot_backfill_info.is_some())
}) {
// route to a repair/recreate path instead of failing injection
} Prevention
- Persist snapshot backfill info atomically with the job's fragment graph.
- Run meta-state consistency checks during startup recovery.
- Keep backups of the meta store before upgrades.
When it happens
Trigger: Recovery/inject-initial-barrier over a snapshot backfill job whose persisted fragment infos contain no fragment with snapshot backfill type info.
Common situations: Meta recovery after crash/upgrade; metadata written by an older version without snapshot backfill info; corrupted or partially persisted fragment graph for the job.
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
- batch refresh job {} has no snapshot backfill info
- recovered snapshot backfill job {} to upstream {} has not se
- snapshot epoch {} to upstream {} different to snapshot epoch
- snapshot backfill job {} has not set snapshot epoch
- cluster under recovery[{}]
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9ecfb06f84fb377d.
Report an issue: GitHub.