{"record":{"id":"8e061c7879f53e9e","repo":"risingwavelabs/risingwave","slug":"expected-rownumberstate-got-other","errorCode":null,"errorMessage":"expected RowNumberState, got {other:?}","messagePattern":"expected RowNumberState, got (.+?)","errorType":"error_code","errorClass":"ExprError::Internal","httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/window_function/rank.rs","lineNumber":73,"sourceCode":"impl RankFuncCount for RowNumber {\n    fn count(&mut self, _curr_key: StateKey) -> i64 {\n        let curr_rank = self.prev_rank + 1;\n        self.prev_rank = curr_rank;\n        curr_rank\n    }\n\n    fn to_proto_state(&self) -> FunctionState {\n        FunctionState::RowNumberState(RowNumberState {\n            prev_rank: self.prev_rank,\n        })\n    }\n\n    fn from_proto_state(state: FunctionState) -> Result<Self> {\n        match state {\n            FunctionState::RowNumberState(s) => Ok(Self {\n                prev_rank: s.prev_rank,\n            }),\n            other => Err(ExprError::Internal(anyhow::anyhow!(\n                \"expected RowNumberState, got {other:?}\"\n            ))),\n        }\n    }\n}\n\n#[derive(EstimateSize)]\npub(super) struct Rank {\n    prev_order_key: Option<MemcmpEncoded>,\n    prev_rank: i64,\n    // 1-based position of the previously output row within its peer group.\n    // Used to advance the rank by the peer-group size when a new group starts.\n    prev_pos_in_peer_group: i64,\n}\n\nimpl Default for Rank {\n    fn default() -> Self {\n        Self {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/window_function/rank.rs#L55-L91","documentation":"`RowNumber` window function state is deserialized from a protobuf `FunctionState`. If the received state variant is anything other than `FunctionState::RowNumberState`, the state does not match the function and deserialization fails with this internal error.","triggerScenarios":"`RowNumber::from_proto_state` receiving a FunctionState of a different variant (e.g. RankState or DenseRankState), typically from a mismatched state type written under the same state key during recovery or a bug in state serialization.","commonSituations":"Stream recovery after a schema/state version change; swapping a window function kind in a materialized view without full rebuild; corrupted or mismatched checkpoint state.","solutions":["Full-rebuild / recreate the materialized view so state matches the current function kind","Verify the state key maps to the correct function type in the streaming plan","Check protobuf FunctionState encoding for version mismatch bugs"],"exampleFix":"// before\nother => Err(ExprError::Internal(anyhow::anyhow!(\"expected RowNumberState, got {other:?}\"))),\n// after\nFunctionState::RowNumberState(_) | FunctionState::RankState(_) => ... // handle variants explicitly, or add a default fallback","handlingStrategy":"try-catch","validationCode":"fn state_matches(state: &FunctionState) -> bool { matches!(state, FunctionState::RowNumberState(_)) }","typeGuard":"fn as_row_number_state(s: &FunctionState) -> Option<&RowNumberState> { match s { FunctionState::RowNumberState(x) => Some(x), _ => None } }","tryCatchPattern":"match RowNumber::from_proto_state(state) {\n    Err(e) if e.to_string().contains(\"expected RowNumberState\") => rebuild_mv_state(),\n    other => other?,\n}","preventionTips":["Never alter a window function kind without full-rebuilding the materialized view","Version the persisted FunctionState and migrate on upgrade","Use distinct state keys per function kind"],"tags":["window-function","state","deserialization"],"backgroundTag":"protobuf-unmarshal-failed","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"}