{"record":{"id":"c01294569a6af172","repo":"risingwavelabs/risingwave","slug":"time-column-should-be-timestamp-or-timestamptz","errorCode":null,"errorMessage":"Time column should be Timestamp or Timestamptz","messagePattern":"Time column should be Timestamp or Timestamptz","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/eowc/eowc_gap_fill.rs","lineNumber":204,"sourceCode":"            }\n        }\n\n        // Generate filled rows, applying the appropriate strategy for each column\n        while fill_time < curr_time {\n            let mut new_row_data = Vec::with_capacity(prev_row.len());\n\n            for col_idx in 0..prev_row.len() {\n                let datum = if col_idx == time_column_index {\n                    // Time column: use the incremented timestamp\n                    let fill_time_scalar = match prev_time_scalar {\n                        ScalarRefImpl::Timestamp(_) => ScalarImpl::Timestamp(fill_time),\n                        ScalarRefImpl::Timestamptz(_) => {\n                            let micros = fill_time.0.and_utc().timestamp_micros();\n                            ScalarImpl::Timestamptz(\n                                risingwave_common::types::Timestamptz::from_micros_uncheck(micros),\n                            )\n                        }\n                        _ => unreachable!(\"Time column should be Timestamp or Timestamptz\"),\n                    };\n                    Some(fill_time_scalar)\n                } else if partition_col_mask[col_idx] {\n                    prev_row.datum_at(col_idx).to_owned_datum()\n                } else if let Some(strategy) = fill_columns.get(&col_idx) {\n                    // Apply the fill strategy for this column\n                    match strategy {\n                        FillStrategy::Locf => prev_row.datum_at(col_idx).to_owned_datum(),\n                        FillStrategy::Null => None,\n                        FillStrategy::Interpolate => {\n                            // Apply interpolation step and update cumulative value\n                            if let Some(step) = &interpolation_steps[col_idx] {\n                                apply_interpolation_step(&mut interpolation_states[col_idx], step);\n                                interpolation_states[col_idx].clone()\n                            } else {\n                                // If interpolation step is None, fill with NULL\n                                None\n                            }","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/eowc/eowc_gap_fill.rs#L186-L222","documentation":"In the EOWC (emit-on-window-close) gap-fill executor, `generate_filled_rows` fills gaps in the output by advancing the time column. The code matches on the time column's scalar ref type and only handles Timestamp and Timestamptz; any other type falls into `_ => unreachable!(\"Time column should be Timestamp or Timestamptz\")`. The executor assumes the schema was already validated so the gap-fill time column is a temporal type.","triggerScenarios":"Running an EMIT ON WINDOW CLOSE gap-fill query whose time column (the column being advanced by the gap interval) is not Timestamp or Timestamptz — e.g., a Date, Int, or Varchar column used as the fill time, while a gap interval is configured.","commonSituations":"Defining a gap-fill materialized view over a source where the event-time column was inferred as VARCHAR or BIGINT instead of TIMESTAMP; or a schema change upstream (connector emits a different type) that silently changes the column type after the MV was created.","solutions":["Cast the gap-fill time column to TIMESTAMP or TIMESTAMPTZ in the query, e.g. `time_col::timestamptz`, before applying gap fill.","Check the source schema with `SHOW COLUMNS FROM <source>` and fix the connector/protobuf definition so the event time is declared as a timestamp type.","If the schema changed after MV creation, recreate the materialized view against the corrected source schema.","Report as a bug if the column is genuinely TIMESTAMP — this implies a validation gap between planning and execution."],"exampleFix":"// before: gap fill on an untyped column\nCREATE MATERIALIZED VIEW mv WITH (gap_fill...) AS SELECT ts_col FROM src;\n// after: ensure a temporal type\nCREATE MATERIALIZED VIEW mv WITH (gap_fill...) AS SELECT ts_col::timestamptz AS ts_col FROM src;","handlingStrategy":"validation","validationCode":"-- Verify the gap-fill time column type before creating the MV:\nSHOW COLUMNS FROM src;\n-- Ensure the time column is TIMESTAMP or TIMESTAMPTZ; cast if not:\nSELECT ts_col::timestamptz IS NOT NULL AS ok FROM src LIMIT 1;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always define the event-time column as TIMESTAMP/TIMESTAMPTZ at the source.","Cast ambiguous columns explicitly in the MV definition.","Re-check source schemas after connector/protobuf changes."],"tags":["streaming","gap-fill","type-mismatch","rust","panic"],"backgroundTag":"type-mismatch","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"}