risingwavelabs/risingwave · error · ExprError::Internal

expected RankState, got {other:?}

Error message

expected RankState, got {other:?}

What it means

`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.

Source

Thrown at src/expr/impl/src/window_function/rank.rs:132

        curr_rank
    }

    fn to_proto_state(&self) -> FunctionState {
        FunctionState::RankState(RankStateProto {
            prev_order_key: self.prev_order_key.as_ref().map(|k| k.to_vec()),
            prev_rank: self.prev_rank,
            prev_pos_in_peer_group: self.prev_pos_in_peer_group,
        })
    }

    fn from_proto_state(state: FunctionState) -> Result<Self> {
        match state {
            FunctionState::RankState(s) => Ok(Self {
                prev_order_key: s.prev_order_key.map(Into::into),
                prev_rank: s.prev_rank,
                prev_pos_in_peer_group: s.prev_pos_in_peer_group,
            }),
            other => Err(ExprError::Internal(anyhow::anyhow!(
                "expected RankState, got {other:?}"
            ))),
        }
    }
}

#[derive(Default, EstimateSize)]
pub(super) struct DenseRank {
    prev_order_key: Option<MemcmpEncoded>,
    prev_rank: i64,
}

impl RankFuncCount for DenseRank {
    fn count(&mut self, curr_key: StateKey) -> i64 {
        let curr_rank = if let Some(prev_order_key) = self.prev_order_key.as_ref()
            && prev_order_key == &curr_key.order_key
        {
            // current key is in the same peer group as the previous one

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Rebuild the materialized view to regenerate consistent state
  2. Confirm the state table used by this Rank function was not written by another function
  3. Audit FunctionState serialization/versioning for mismatches

Example fix

// before
other => Err(ExprError::Internal(anyhow::anyhow!("expected RankState, got {other:?}"))),
// after
// ensure the executor constructs the matching state type:
let state = FunctionState::RankState(RankState { .. }); // must match the function kind
Defensive patterns

Strategy: try-catch

Validate before calling

fn state_matches(state: &FunctionState) -> bool { matches!(state, FunctionState::RankState(_)) }

Type guard

fn as_rank_state(s: &FunctionState) -> Option<&RankState> { match s { FunctionState::RankState(x) => Some(x), _ => None } }

Try / catch

match Rank::from_proto_state(state) {
    Err(e) if e.to_string().contains("expected RankState") => rebuild_mv_state(),
    other => other?,
}

Prevention

When it happens

Trigger: `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.

Common situations: State-key collisions after plan changes; restoring checkpoints from a cluster running a different function set; migration between RisingWave versions.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/741856b77831dbd4. Report an issue: GitHub.