{"record":{"id":"14bc9b8f80e471ca","repo":"risingwavelabs/risingwave","slug":"batch-refresh-job-has-no-snapshot-backfill-info","errorCode":null,"errorMessage":"batch refresh job {} has no snapshot backfill info","messagePattern":"batch refresh job (.+?) has no snapshot backfill info","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/meta/src/barrier/rpc.rs","lineNumber":744,"sourceCode":"                                    )\n                                })\n                                .collect(),\n                        )\n                    })\n            })\n            .collect();\n\n        // Batch-refresh jobs are rendered outside `jobs`, but their upstream tables\n        // must still start with log-store-enabled subscribers after recovery.\n        for (job_id, render_result) in &batch_refresh {\n            let snapshot_backfill_info = StreamFragmentGraph::collect_snapshot_backfill_info_impl(\n                render_result\n                    .fragment_infos\n                    .values()\n                    .map(|fragment| (&fragment.nodes, fragment.fragment_type_mask)),\n            )?\n            .0\n            .ok_or_else(|| anyhow!(\"batch refresh job {} has no snapshot backfill info\", job_id))?;\n\n            for upstream_table_id in snapshot_backfill_info\n                .upstream_mv_table_id_to_backfill_epoch\n                .keys()\n            {\n                subscribers\n                    .entry(*upstream_table_id)\n                    .or_default()\n                    .try_insert(job_id.as_subscriber_id(), SubscriberType::SnapshotBackfill)\n                    .expect(\"non-duplicate\");\n            }\n        }\n\n        let mut database_jobs = HashMap::new();\n        let mut snapshot_backfill_jobs = HashMap::new();\n\n        for (job_id, job_fragments) in jobs {\n            if creating_jobs.remove(&job_id) {","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/barrier/rpc.rs#L726-L762","documentation":"During `inject_database_initial_barrier`, for a batch refresh job the meta service computes snapshot backfill info from the job's fragment graph, then `.ok_or_else` fails when no fragment carries snapshot-backfill state. It is an internal invariant: a batch refresh job must have exactly one snapshot backfill node, so its absence is a corrupted/incomplete job description.","triggerScenarios":"`inject_database_initial_barrier` processing a batch refresh job whose resolved fragment graph yields no snapshot backfill info (fragment type mask lookup returns None).","commonSituations":"Metadata inconsistency after partial recovery or upgrade; job created/modified by code path that didn't register the snapshot backfill node; corrupt object store state for the job's fragments.","solutions":["Inspect the job's fragment metadata in the meta store; confirm the snapshot backfill fragment exists and its type mask is set.","Re-create or re-issue the batch refresh job if its fragment graph is inconsistent.","Check for version skew: ensure meta nodes and frontend run versions that set snapshot backfill info when creating batch refresh jobs.","File a bug with the job_id and fragment dump if a freshly created job hits this."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before injecting, assert the job has snapshot backfill info\nfn has_snapshot_backfill_info(fragment_infos: &BTreeMap<u32, StreamFragmentInfo>) -> bool {\n    fragment_infos.values().any(|f| {\n        f.nodes.values().any(|n| {\n            n.node.as_ref()\n                .map(|n| n.snapshot_backfill_info.is_some())\n                .unwrap_or(false)\n        })\n    })\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure job creation always registers a snapshot backfill fragment for batch refresh jobs.","Validate fragment type masks when persisting a job's fragment graph.","Monitor meta store consistency after upgrades."],"tags":["meta","barrier","backfill","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}