risingwavelabs/risingwave · error · ExprError::Internal

expected DenseRankState, got {other:?}

Error message

expected DenseRankState, got {other:?}

What it means

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

Source

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

        self.prev_order_key = Some(curr_key.order_key);
        self.prev_rank = curr_rank;
        curr_rank
    }

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

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

/// Generic state for rank window functions including `row_number`, `rank` and `dense_rank`.
#[derive(EstimateSize)]
pub(super) struct RankState<RF: RankFuncCount> {
    /// First state key of the partition.
    first_key: Option<StateKey>,
    /// State keys that are waiting to be outputted.
    buffer: EstimatedVecDeque<StateKey>,
    /// Function-specific state.
    func_state: RF,
    /// Whether persistence is enabled for this state.
    persistence_enabled: bool,
    /// The key of the last output row (for snapshot).

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Recreate / full-rebuild the materialized view so state matches the function kind
  2. Verify state keys are not shared between different window functions
  3. Check RisingWave version consistency across the cluster when restoring state

Example fix

// before
other => Err(ExprError::Internal(anyhow::anyhow!("expected DenseRankState, got {other:?}"))),
// after
// ensure plan and state agree: use FunctionState::DenseRankState when writing state for DENSE_RANK
Defensive patterns

Strategy: try-catch

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

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

Common situations: Altering a materialized view from RANK to DENSE_RANK without rebuild; state corruption or version skew between nodes.

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/ae5b32788a88817a. Report an issue: GitHub.