risingwavelabs/risingwave · error

invalid backfill state: cdc_offset_high

Error message

invalid backfill state: cdc_offset_high

What it means

Thrown by CdcBackfillStateV2::restore_state when element [4] of the persisted state row is neither a Jsonb-encoded CDC offset nor null, so cdc_offset_high cannot be deserialized. Same guard as cdc_offset_low but for the high watermark offset.

Source

Thrown at src/stream/src/executor/backfill/cdc/state_v2.rs:89

                };
                let row_count = match state[2] {
                    Some(ScalarImpl::Int64(val)) => val,
                    _ => return Err(anyhow!("invalid backfill state: row_count").into()),
                };
                let (cdc_offset_low, cdc_offset_high) = if !self.is_legacy_state {
                    let cdc_offset_low = match state[3] {
                        Some(ScalarImpl::Jsonb(ref jsonb)) => {
                            serde_json::from_value(jsonb.clone().take()).unwrap()
                        }
                        None => None,
                        _ => return Err(anyhow!("invalid backfill state: cdc_offset_low").into()),
                    };
                    let cdc_offset_high = match state[4] {
                        Some(ScalarImpl::Jsonb(ref jsonb)) => {
                            serde_json::from_value(jsonb.clone().take()).unwrap()
                        }
                        None => None,
                        _ => return Err(anyhow!("invalid backfill state: cdc_offset_high").into()),
                    };
                    (cdc_offset_low, cdc_offset_high)
                } else {
                    (None, None)
                };

                Ok(CdcStateRecord {
                    is_finished,
                    row_count,
                    cdc_offset_low,
                    cdc_offset_high,
                })
            }
            None => Ok(CdcStateRecord::default()),
        }
    }

    /// Modify the state of the corresponding split

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Cancel and recreate the streaming job to rebuild the backfill state
  2. Align all nodes on one RisingWave version so state encoding is consistent
  3. Inspect the internal state table row to confirm the cdc_offset_high field type
  4. Recreate the CDC table/MV from the upstream if the persisted state is unrecoverable
Defensive patterns

Strategy: validation

Validate before calling

let high_ok = matches!(state[STATE_OFFSET_HIGH_IDX], None | Some(ScalarImpl::Jsonb(_)));
if !high_ok { /* recreate the streaming job */ }

Prevention

When it happens

Trigger: Restoring a non-legacy v2 CDC backfill state where state[4] holds a scalar other than Jsonb/None, e.g. a row written by an incompatible encoder or a truncated write.

Common situations: Version mismatch after upgrade; legacy rows read by v2 executor; state corruption from interrupted persistence.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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