risingwavelabs/risingwave · error
invalid backfill state: cdc_offset_low
Error message
invalid backfill state: cdc_offset_low
What it means
Thrown by CdcBackfillStateV2::restore_state when element [3] of the persisted state row is neither a Jsonb-encoded CDC offset nor null, so cdc_offset_low cannot be deserialized. The code accepts Some(Jsonb) and None; any other scalar is rejected.
Source
Thrown at src/stream/src/executor/backfill/cdc/state_v2.rs:82
{
Some(row) => {
tracing::info!("restored cdc backfill state: {:?}", row);
let state = row.into_inner().into_vec();
let is_finished = match state[1] {
Some(ScalarImpl::Bool(val)) => val,
_ => return Err(anyhow!("invalid backfill state: backfill_finished").into()),
};
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,View on GitHub (pinned to 6469eb736d)
Solutions
- Cancel and recreate the streaming job so the backfill state is rebuilt
- Ensure all nodes run the same RisingWave version (rolling upgrades must not mix old/new state encoders for the same job)
- Inspect the internal state table row to confirm the offset field type
- Drop and recreate the CDC table/MV from the upstream source if state is unusable
Defensive patterns
Strategy: validation
Validate before calling
let low_ok = matches!(state[STATE_OFFSET_LOW_IDX], None | Some(ScalarImpl::Jsonb(_)));
if !low_ok { /* state written by incompatible encoder; recreate */ } Prevention
- Ensure all compute nodes run the same RisingWave build
- Complete backfill before failover/scale operations where possible
When it happens
Trigger: Restoring a non-legacy v2 CDC backfill state where state[3] holds a scalar other than Jsonb/None, e.g. a Bytea offset from a legacy layout or a partially-written row.
Common situations: Mixed-version clusters where the state writer and reader disagree on offset encoding; migration bugs; corrupted state after crash during state update.
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
- invalid backfill state: cdc_offset_high
- invalid backfill state: cdc_offset
- invalid backfill state: backfill_finished
- invalid backfill state: row_count
- unsupported JSON number: {v}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/b7c21946047e0498.
Report an issue: GitHub.