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

  1. Verify the job_id exists and is a streaming job: query the fragments table for the job before calling this API.
  2. Check the meta store for orphaned or duplicated mview fragments; clean inconsistent rows or re-create the job.
  3. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/9d7b2e1b8581f202. Report an issue: GitHub.