risingwavelabs/risingwave · error · MetaError
expected exactly one mview fragment for job {}, found {}
Error message
expected exactly one mview fragment for job {}, found {} What it means
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.
Source
Thrown at src/meta/src/controller/fragment.rs:2053
pub async fn get_mview_fragment_by_id(&self, job_id: JobId) -> MetaResult<FragmentId> {
let inner = self.inner.read().await;
let txn = inner.db.begin().await?;
let mview_fragment: Vec<FragmentId> = FragmentModel::find()
.select_only()
.column(fragment::Column::FragmentId)
.filter(
fragment::Column::JobId
.eq(job_id)
.and(FragmentTypeMask::intersects(FragmentTypeFlag::Mview)),
)
.into_tuple()
.all(&txn)
.await?;
if mview_fragment.len() != 1 {
return Err(anyhow::anyhow!(
"expected exactly one mview fragment for job {}, found {}",
job_id,
mview_fragment.len()
)
.into());
}
Ok(mview_fragment.into_iter().next().unwrap())
}
pub async fn has_table_been_migrated(&self, table_id: TableId) -> MetaResult<bool> {
let inner = self.inner.read().await;
let txn = inner.db.begin().await?;
has_table_been_migrated(&txn, table_id).await
}
pub async fn update_fragment_splits<C>(
&self,View on GitHub (pinned to 6469eb736d)
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.
Example fix
// before
let frags = controller.get_mview_fragments(job_id).await?; // panics later with found 0
// after
let frags = controller.get_mview_fragments(job_id).await?;
if frags.is_empty() { bail!("job {} has no fragments; check the job exists", job_id); } Defensive patterns
Strategy: validation
Validate before calling
let count = txn.find_fragments_by_job_id(job_id).await?.len();
if count != 1 {
bail!("job {} must have exactly one mview fragment, found {}", job_id, count);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
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
- Failed to retrieve fragment description: fragment {} (job_id
- fragments {:?} not found
- table_fragment does not exist: id={0}
- backup job status not found: job {}, {}
- backup job failed: job {}, {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9d7b2e1b8581f202.
Report an issue: GitHub.