risingwavelabs/risingwave · error · MetaError
expected exactly one mview fragment for table
Error message
expected exactly one mview fragment for table {}, found {} What it means
The helper expects a materialized-view (mview) fragment to exist for the given table — exactly one — because streaming tables are backed by a single mview fragment. If zero or multiple fragments are found, it bails with "expected exactly one mview fragment for table {}, found {}".
Solutions
- Verify the table_id actually corresponds to a streaming/materialized table; skip non-streaming tables before calling this helper.
- Recreate the table or MV if its fragment rows are missing after a failed creation; check catalog tables for duplicates and clean them.
- Retry after in-flight DDL completes if the read raced with table creation.
- If duplicates persist post-upgrade, run the catalog repair/migration tooling for fragment metadata.
Defensive patterns
Strategy: validation
Validate before calling
// Only call for streaming-backed tables
if !is_streaming_table(table_id) { return Ok(()); } // skip plain tables
let n = count_mview_fragments(table_id).await?;
assert_eq!(n, 1, "table {} has {} mview fragments", table_id, n); Prevention
- Check that the table is a materialized/streaming table before expecting an mview fragment
- Recreate tables whose creation may have failed midway, leaving fragment rows missing/duplicated
- Run catalog consistency checks after crash recovery or upgrades
When it happens
Trigger: Querying fragments for `table_id` when the table has no mview fragment (plain table without streaming topology, or catalog rows missing after failed creation), or when duplicates exist after a partial create/recovery.
Common situations: Corrupted or partially migrated catalog after crashes or upgrades; calling the helper on a non-streaming table by mistake; concurrent DDL observed mid-materialization by internal tooling.
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
- expected exactly one sink fragment for each sink, but got
- batch refresh job has no snapshot backfill info
- catalog object has no database
- job fragments should exist for streaming job
- missing system param
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/01d1b1e541a1fd2c.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/controller/utils.rs:2418
pub async fn has_table_been_migrated<C>(txn: &C, table_id: TableId) -> MetaResult<bool>
where
C: ConnectionTrait,
{
let mview_fragment: Vec<i32> = Fragment::find()
.select_only()
.column(fragment::Column::FragmentTypeMask)
.filter(
fragment::Column::JobId
.eq(table_id)
.and(FragmentTypeMask::intersects(FragmentTypeFlag::Mview)),
)
.into_tuple()
.all(txn)
.await?;
let mview_fragment_len = mview_fragment.len();
if mview_fragment_len != 1 {
bail!(
"expected exactly one mview fragment for table {}, found {}",
table_id,
mview_fragment_len
);
}
let mview_fragment = mview_fragment.into_iter().next().unwrap();
let migrated =
FragmentTypeMask::from(mview_fragment).contains(FragmentTypeFlag::UpstreamSinkUnion);
Ok(migrated)
}
pub async fn check_if_belongs_to_iceberg_table<C>(txn: &C, job_id: JobId) -> MetaResult<bool>
where
C: ConnectionTrait,
{
if let Some(engine) = Table::find_by_id(job_id.as_mv_table_id())View on GitHub (pinned to 6469eb736d)