{"record":{"id":"ae5b32788a88817a","repo":"risingwavelabs/risingwave","slug":"expected-denserankstate-got-other","errorCode":null,"errorMessage":"expected DenseRankState, got {other:?}","messagePattern":"expected DenseRankState, got (.+?)","errorType":"error_code","errorClass":"ExprError::Internal","httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/window_function/rank.rs","lineNumber":174,"sourceCode":"        self.prev_order_key = Some(curr_key.order_key);\n        self.prev_rank = curr_rank;\n        curr_rank\n    }\n\n    fn to_proto_state(&self) -> FunctionState {\n        FunctionState::DenseRankState(DenseRankState {\n            prev_order_key: self.prev_order_key.as_ref().map(|k| k.to_vec()),\n            prev_rank: self.prev_rank,\n        })\n    }\n\n    fn from_proto_state(state: FunctionState) -> Result<Self> {\n        match state {\n            FunctionState::DenseRankState(s) => Ok(Self {\n                prev_order_key: s.prev_order_key.map(Into::into),\n                prev_rank: s.prev_rank,\n            }),\n            other => Err(ExprError::Internal(anyhow::anyhow!(\n                \"expected DenseRankState, got {other:?}\"\n            ))),\n        }\n    }\n}\n\n/// Generic state for rank window functions including `row_number`, `rank` and `dense_rank`.\n#[derive(EstimateSize)]\npub(super) struct RankState<RF: RankFuncCount> {\n    /// First state key of the partition.\n    first_key: Option<StateKey>,\n    /// State keys that are waiting to be outputted.\n    buffer: EstimatedVecDeque<StateKey>,\n    /// Function-specific state.\n    func_state: RF,\n    /// Whether persistence is enabled for this state.\n    persistence_enabled: bool,\n    /// The key of the last output row (for snapshot).","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/window_function/rank.rs#L156-L192","documentation":"`DenseRank` window function state is deserialized only from `FunctionState::DenseRankState`. Any other variant means the persisted state does not belong to this function and deserialization fails with this internal error.","triggerScenarios":"`DenseRank::from_proto_state` receiving a different FunctionState variant — mismatch between the function kind and the stored state, typically during stream recovery or after changing the window function definition.","commonSituations":"Altering a materialized view from RANK to DENSE_RANK without rebuild; state corruption or version skew between nodes.","solutions":["Recreate / full-rebuild the materialized view so state matches the function kind","Verify state keys are not shared between different window functions","Check RisingWave version consistency across the cluster when restoring state"],"exampleFix":"// before\nother => Err(ExprError::Internal(anyhow::anyhow!(\"expected DenseRankState, got {other:?}\"))),\n// after\n// ensure plan and state agree: use FunctionState::DenseRankState when writing state for DENSE_RANK","handlingStrategy":"try-catch","validationCode":"fn state_matches(state: &FunctionState) -> bool { matches!(state, FunctionState::DenseRankState(_)) }","typeGuard":"fn as_dense_rank_state(s: &FunctionState) -> Option<&DenseRankState> { match s { FunctionState::DenseRankState(x) => Some(x), _ => None } }","tryCatchPattern":"match DenseRank::from_proto_state(state) {\n    Err(e) if e.to_string().contains(\"expected DenseRankState\") => rebuild_mv_state(),\n    other => other?,\n}","preventionTips":["Do not swap RANK/DENSE_RANK in place; recreate the object","Keep RisingWave versions consistent when restoring checkpoints","Test recovery of window aggregates after plan changes"],"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"}