{"record":{"id":"db9c04c7bfa17d81","repo":"risingwavelabs/risingwave","slug":"watermark-should-not-be-produced-by-a-table-functi","errorCode":null,"errorMessage":"Watermark should not be produced by a table function","messagePattern":"Watermark should not be produced by a table function","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/project/project_set.rs","lineNumber":305,"sourceCode":"    }\n\n    async fn handle_watermark(&self, watermark: Watermark) -> StreamExecutorResult<Vec<Watermark>> {\n        let expr_indices = match self.watermark_derivations.get_vec(&watermark.col_idx) {\n            Some(v) => v,\n            None => return Ok(vec![]),\n        };\n        let mut ret = vec![];\n        for expr_idx in expr_indices {\n            let expr_idx = *expr_idx;\n            let derived_watermark = match &self.select_list[expr_idx] {\n                ProjectSetSelectItem::Scalar(expr) => {\n                    watermark\n                        .clone()\n                        .transform_with_expr(expr, expr_idx + PROJ_ROW_ID_OFFSET)\n                        .await\n                }\n                ProjectSetSelectItem::Set(_) => {\n                    bail!(\"Watermark should not be produced by a table function\");\n                }\n            };\n\n            if let Some(derived_watermark) = derived_watermark {\n                ret.push(derived_watermark);\n            } else {\n                warn!(\n                    \"a NULL watermark is derived with the expression {}!\",\n                    expr_idx\n                );\n            }\n        }\n        Ok(ret)\n    }\n}\n\n/// Either a scalar expression or a set-returning function.\n///","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/project/project_set.rs#L287-L323","documentation":"In a ProjectSet (project with table functions), watermarks can only be transformed by scalar select items. When the project's watermark expression lands on a `Set` item (a table function), there is no single output row to carry a derived watermark, so the executor bails with this error. Table functions expand one input row to many rows, which makes watermark propagation ill-defined.","triggerScenarios":"Building/planning a streaming pipeline whose watermark columns pass through a table function (e.g. generate_series, unnest) inside a ProjectSet, so `handle_watermark` meets a `ProjectSetSelectItem::Set` at the watermark's expr index.","commonSituations":"Defining a source/table with watermark columns and then joining/aliasing through table-function expressions in the streaming query; planner bugs letting a watermark expr reference a table-function output.","solutions":["Restructure the query so the watermark column comes from a scalar projection, not a table function output (e.g. compute the watermark column before applying the table function)","Remove the watermark declaration on that column if it is not needed downstream","Split the query: materialize the table-function output first, then define watermarks on the materialized result","If the planner emitted this shape automatically, file an issue with the SQL query"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- Validate at query-design time: the watermark column must come from a scalar projection\n-- Ensure no table function (generate_series, unnest, ...) sits between the source watermark column and its consumers\nSELECT column_name FROM watermarked_columns\nWHERE column_name NOT IN (SELECT output_col_of_table_function);","typeGuard":null,"tryCatchPattern":"match pipeline_build {\n    Err(e) if e.to_string().contains(\"Watermark should not be produced by a table function\") => {\n        // Rewrite the query: emit the watermark column via scalar projection before the table function\n        rewrite_query_without_watermark_through_tvf();\n    }\n    other => other?,\n}","preventionTips":["Define watermarks only on plain columns of the source/table, never on table-function outputs","Compute derived watermark columns in a scalar projection upstream of any table function","If watermarks through table functions are needed, materialize the function output first and redeclare watermarks there","Review query plans for ProjectSet items before enabling watermark propagation"],"tags":["rust","streaming","watermark","table-function"],"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"}