{"record":{"id":"c09739249753524d","repo":"risingwavelabs/risingwave","slug":"multiple-clean-watermark-columns-are-not-supported","errorCode":null,"errorMessage":"multiple clean watermark columns are not supported yet","messagePattern":"multiple clean watermark columns are not supported yet","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/stream/src/common/table/state_table.rs","lineNumber":829,"sourceCode":"            table_catalog\n                .get_dist_key_in_pk()\n                .iter()\n                .map(|idx| *idx as usize)\n                .collect()\n        };\n\n        let vnode_col_idx_in_pk = table_catalog.vnode_col_index.as_ref().and_then(|idx| {\n            let vnode_col_idx = *idx as usize;\n            pk_indices.iter().position(|&i| vnode_col_idx == i)\n        });\n        let value_indices = table_catalog\n            .value_indices\n            .iter()\n            .map(|val| *val as usize)\n            .collect_vec();\n        let clean_watermark_indices = table_catalog.get_clean_watermark_column_indices();\n        if clean_watermark_indices.len() > 1 {\n            unimplemented!(\"multiple clean watermark columns are not supported yet\")\n        }\n        let clean_watermark_index = clean_watermark_indices.first().map(|&i| i as usize);\n\n        Self {\n            table_id,\n            table_name_for_debug: table_catalog.name.clone(),\n            table_columns,\n            order_types,\n            pk_indices,\n            dist_key_in_pk_indices,\n            vnode_col_idx_in_pk,\n            expected_vnode_count: table_catalog.vnode_count(),\n            value_indices,\n            prefix_hint_len: table_catalog.read_prefix_len_hint as usize,\n            retention_seconds: table_catalog.retention_seconds,\n            versioned: table_catalog.version.is_some(),\n            fragment_id: table_catalog.fragment_id,\n            clean_watermark_index,","sourceCodeStart":811,"sourceCodeEnd":847,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/common/table/state_table.rs#L811-L847","documentation":"When constructing a `StateTable` from a `TableCatalog`, RisingWave supports at most one column designated as a clean watermark column. If the catalog declares more than one (`get_clean_watermark_column_indices().len() > 1`), `unimplemented!` panics because the state table's watermark-rewrite machinery only handles a single clean watermark index. This is a feature-completeness guard, not a data corruption error.","triggerScenarios":"Creating a table, materialized view, or sink whose `TableCatalog` has two or more columns flagged as clean watermark columns — e.g. a MV with multiple watermark definitions used as a state table.","commonSituations":"SQL like `CREATE MATERIALIZED VIEW ... WITH (watermark = ...)` on multiple columns feeding one state table, or internal catalog construction that sets clean watermark columns on more than one value column; attempting features not yet supported by the current RisingWave version.","solutions":["Redesign the table/MV to define at most one watermark column; pick the single column that should drive watermark cleaning.","If multiple watermark columns are truly needed, check RisingWave release notes/roadmap for multi-clean-watermark support and upgrade.","Inspect the generated catalog (`SHOW CREATE ...` or the meta catalog dump) to find which planner step added the extra clean watermark column, and adjust the query.","This is a panic (unimplemented), so it cannot be caught at runtime — it must be fixed at the catalog/query level."],"exampleFix":"-- before\nCREATE MATERIALIZED VIEW mv WITH (watermark = ts_a) AS SELECT ... ; -- plus a second watermark column added internally\n-- after\nCREATE MATERIALIZED VIEW mv WITH (watermark = ts_a) AS SELECT ts_a, ts_b, ... ; -- only one clean watermark column","handlingStrategy":"validation","validationCode":"// Check the catalog before building the state table\nlet n = table_catalog.get_clean_watermark_column_indices().len();\nif n > 1 {\n    return Err(format!(\"table '{}' has {n} clean watermark columns; only 1 is supported\", table_catalog.name));\n}","typeGuard":"// Rust\nfn has_single_clean_watermark(catalog: &TableCatalog) -> bool {\n    catalog.get_clean_watermark_column_indices().len() == 1\n}","tryCatchPattern":"// This panics via unimplemented! and cannot be caught — validate the catalog beforehand.\n// Wrap table construction behind a pre-check:\nif !has_single_clean_watermark(&catalog) {\n    return Err(StreamExecutorError::from(anyhow!(\"multi clean watermark table not supported\")));\n}\nlet table = StateTable::from_table_catalog(&catalog);","preventionTips":["Define at most one watermark column per table/materialized view","Review generated catalogs (SHOW CREATE / catalog dump) for accidental multiple watermark columns","Check RisingWave docs for watermark feature limits before using multiple watermarks","Add a catalog-level validation step in CI for DDL with watermark clauses"],"tags":["streaming","watermark","unimplemented","catalog"],"backgroundTag":"unsupported-operation","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"}