{"record":{"id":"741856b77831dbd4","repo":"risingwavelabs/risingwave","slug":"expected-rankstate-got-other","errorCode":null,"errorMessage":"expected RankState, got {other:?}","messagePattern":"expected RankState, got (.+?)","errorType":"error_code","errorClass":"ExprError::Internal","httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/window_function/rank.rs","lineNumber":132,"sourceCode":"        curr_rank\n    }\n\n    fn to_proto_state(&self) -> FunctionState {\n        FunctionState::RankState(RankStateProto {\n            prev_order_key: self.prev_order_key.as_ref().map(|k| k.to_vec()),\n            prev_rank: self.prev_rank,\n            prev_pos_in_peer_group: self.prev_pos_in_peer_group,\n        })\n    }\n\n    fn from_proto_state(state: FunctionState) -> Result<Self> {\n        match state {\n            FunctionState::RankState(s) => Ok(Self {\n                prev_order_key: s.prev_order_key.map(Into::into),\n                prev_rank: s.prev_rank,\n                prev_pos_in_peer_group: s.prev_pos_in_peer_group,\n            }),\n            other => Err(ExprError::Internal(anyhow::anyhow!(\n                \"expected RankState, got {other:?}\"\n            ))),\n        }\n    }\n}\n\n#[derive(Default, EstimateSize)]\npub(super) struct DenseRank {\n    prev_order_key: Option<MemcmpEncoded>,\n    prev_rank: i64,\n}\n\nimpl RankFuncCount for DenseRank {\n    fn count(&mut self, curr_key: StateKey) -> i64 {\n        let curr_rank = if let Some(prev_order_key) = self.prev_order_key.as_ref()\n            && prev_order_key == &curr_key.order_key\n        {\n            // current key is in the same peer group as the previous one","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/window_function/rank.rs#L114-L150","documentation":"`Rank` window function state is deserialized from `FunctionState::RankState` only. Any other variant indicates the stored state belongs to a different window function, so deserialization fails with this internal error.","triggerScenarios":"`Rank::from_proto_state` called with e.g. DenseRankState or RowNumberState — mismatched function kind vs. persisted state, usually during recovery or after altering a window function in a materialized view.","commonSituations":"State-key collisions after plan changes; restoring checkpoints from a cluster running a different function set; migration between RisingWave versions.","solutions":["Rebuild the materialized view to regenerate consistent state","Confirm the state table used by this Rank function was not written by another function","Audit FunctionState serialization/versioning for mismatches"],"exampleFix":"// before\nother => Err(ExprError::Internal(anyhow::anyhow!(\"expected RankState, got {other:?}\"))),\n// after\n// ensure the executor constructs the matching state type:\nlet state = FunctionState::RankState(RankState { .. }); // must match the function kind","handlingStrategy":"try-catch","validationCode":"fn state_matches(state: &FunctionState) -> bool { matches!(state, FunctionState::RankState(_)) }","typeGuard":"fn as_rank_state(s: &FunctionState) -> Option<&RankState> { match s { FunctionState::RankState(x) => Some(x), _ => None } }","tryCatchPattern":"match Rank::from_proto_state(state) {\n    Err(e) if e.to_string().contains(\"expected RankState\") => rebuild_mv_state(),\n    other => other?,\n}","preventionTips":["Rebuild materialized views after changing RANK to another window function","Verify state tables after cluster restore","Add assertions that the executor writes the matching FunctionState variant"],"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"}