{"record":{"id":"9d7b2e1b8581f202","repo":"risingwavelabs/risingwave","slug":"expected-exactly-one-mview-fragment-for-job-fo","errorCode":null,"errorMessage":"expected exactly one mview fragment for job {}, found {}","messagePattern":"expected exactly one mview fragment for job (.+?), found (.+?)","errorType":"exception","errorClass":"MetaError","httpStatus":null,"severity":"error","filePath":"src/meta/src/controller/fragment.rs","lineNumber":2053,"sourceCode":"\n    pub async fn get_mview_fragment_by_id(&self, job_id: JobId) -> MetaResult<FragmentId> {\n        let inner = self.inner.read().await;\n        let txn = inner.db.begin().await?;\n\n        let mview_fragment: Vec<FragmentId> = FragmentModel::find()\n            .select_only()\n            .column(fragment::Column::FragmentId)\n            .filter(\n                fragment::Column::JobId\n                    .eq(job_id)\n                    .and(FragmentTypeMask::intersects(FragmentTypeFlag::Mview)),\n            )\n            .into_tuple()\n            .all(&txn)\n            .await?;\n\n        if mview_fragment.len() != 1 {\n            return Err(anyhow::anyhow!(\n                \"expected exactly one mview fragment for job {}, found {}\",\n                job_id,\n                mview_fragment.len()\n            )\n            .into());\n        }\n\n        Ok(mview_fragment.into_iter().next().unwrap())\n    }\n\n    pub async fn has_table_been_migrated(&self, table_id: TableId) -> MetaResult<bool> {\n        let inner = self.inner.read().await;\n        let txn = inner.db.begin().await?;\n        has_table_been_migrated(&txn, table_id).await\n    }\n\n    pub async fn update_fragment_splits<C>(\n        &self,","sourceCodeStart":2035,"sourceCodeEnd":2071,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/controller/fragment.rs#L2035-L2071","documentation":"Thrown by the meta controller when looking up the streaming fragments of a materialized-view/streaming job expects exactly one mview fragment (an MV/table/sink job has exactly one fragment that acts as the mview endpoint), but the transaction returned a different count (0 = job's fragments missing/corrupted; >1 = corrupted state). It is a state-integrity assertion wrapped in a recoverable anyhow error.","triggerScenarios":"Calling the surrounding fragment-loading API (e.g. when resuming/altering a streaming job) with a job_id whose stored fragments contain zero or multiple fragments of the mview type; corrupted or partially-written meta state after failed DDL or a manual DB edit.","commonSituations":"Meta store inconsistency after a crashed CREATE MATERIALIZED VIEW / ALTER, a job id passed that has no fragments (deleted job), or upgrading over a meta store written by an incompatible version.","solutions":["Verify the job_id exists and is a streaming job: query the fragments table for the job before calling this API.","Check the meta store for orphaned or duplicated mview fragments; clean inconsistent rows or re-create the job.","If it happened after a crash mid-DDL, retry the DDL from scratch on a clean job id."],"exampleFix":"// before\nlet frags = controller.get_mview_fragments(job_id).await?; // panics later with found 0\n// after\nlet frags = controller.get_mview_fragments(job_id).await?;\nif frags.is_empty() { bail!(\"job {} has no fragments; check the job exists\", job_id); }","handlingStrategy":"validation","validationCode":"let count = txn.find_fragments_by_job_id(job_id).await?.len();\nif count != 1 {\n    bail!(\"job {} must have exactly one mview fragment, found {}\", job_id, count);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify the job exists and is a streaming job before fetching its fragments","Audit meta-store fragment rows after any failed DDL","Avoid manual edits to the meta store","Catch the returned MetaError rather than treating job state as assumed-good"],"tags":["meta","fragment","state-integrity"],"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"}