risingwavelabs/risingwave · error

decoded epoch not match expected epoch

Error message

decoded epoch {} not match expected epoch {}

What it means

Guard in deserialize_stream_chunk of the KV log store: a decoded row's epoch differs from the epoch expected for the range being decoded. The state-table iteration returned data from the wrong epoch, indicating a corrupt or inconsistent read range; decoding aborts with this error.

Solutions

  1. This indicates corruption or misalignment in the KV log store: a decoded row's epoch differs from the epoch being read.
  2. Verify the state store data integrity for the affected vnode range; re-plan or rebuild the actor so it re-reads from a consistent snapshot.
  3. If reproducible, report with the expected/decoded epochs from the message.
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/stream/src/common/log_store_impl/kv_log_store/serde.rs:463 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at src/stream/src/common/log_store_impl/kv_log_store/serde.rs:463

        let size_bound = (end_seq_id - start_seq_id + 1) as usize;
        let mut data_chunk_builder =
            DataChunkBuilder::new(self.payload_schema.clone(), size_bound + 1);
        let mut ops = Vec::with_capacity(size_bound);
        let mut read_info = ReadInfo::new();
        let stream = select_all(
            iters
                .into_iter()
                .map(|(vnode, iter)| deserialize_stream(vnode, iter, self.clone())),
        );
        pin_mut!(stream);
        while let Some(row) = stream.try_next().await? {
            let epoch = row.row_meta.epoch;
            let op = row.op;
            let row_size = row.row_meta.size;
            match (epoch, op) {
                (epoch, LogStoreOp::Row { op, row, .. }) => {
                    if epoch != expected_epoch {
                        return Err(anyhow!(
                            "decoded epoch {} not match expected epoch {}",
                            epoch,
                            expected_epoch
                        ));
                    }
                    read_info.read_one_row(row_size);
                    ops.push(op);
                    if ops.len() > size_bound {
                        return Err(anyhow!(
                            "row count {} exceed size bound {}",
                            ops.len(),
                            size_bound
                        ));
                    }
                    assert!(data_chunk_builder.append_one_row(row).is_none());
                }
                (
                    epoch,

View on GitHub (pinned to 6469eb736d)