risingwavelabs/risingwave · error
invalid backfill state: unfinished row has null cdc_offset
Error message
invalid backfill state: unfinished row has null cdc_offset
What it means
The CDC backfill state row's final column is `cdc_offset`, stored as Jsonb. A NULL offset is only legal when `backfill_finished` is true (no offset needed). If the offset is NULL while the backfill is unfinished, the executor cannot resume from a position, so `restore_state` returns this error; a non-Jsonb, non-NULL value yields the sibling 'invalid backfill state: cdc_offset' error.
Source
Thrown at src/stream/src/executor/backfill/cdc/state.rs:86
self.cached_state = row.into_inner().into_vec();
let state = self.cached_state.as_slice();
let state_len = state.len();
// schema: | `split_id` | `pk...` | `backfill_finished` | `row_count` | `cdc_offset` |
let row_count = match state[state_len - 2] {
Some(ScalarImpl::Int64(val)) => val,
_ => return Err(anyhow!("invalid backfill state: row_count").into()),
};
let is_finished = match state[state_len - 3] {
Some(ScalarImpl::Bool(val)) => val,
_ => return Err(anyhow!("invalid backfill state: backfill_finished").into()),
};
let cdc_offset = match state[state_len - 1] {
Some(ScalarImpl::Jsonb(ref jsonb)) => {
serde_json::from_value(jsonb.clone().take()).unwrap()
}
None if is_finished => None,
None => {
return Err(anyhow!(
"invalid backfill state: unfinished row has null cdc_offset"
)
.into());
}
_ => return Err(anyhow!("invalid backfill state: cdc_offset").into()),
};
let current_pk_pos = state[1..state_len - 3].to_vec();
Ok(CdcStateRecord {
current_pk_pos: Some(OwnedRow::new(current_pk_pos)),
is_finished,
last_cdc_offset: cdc_offset,
row_count,
})
}
None => Ok(CdcStateRecord::default()),
}
}View on GitHub (pinned to 6469eb736d)
Solutions
- Drop and re-create the CDC table / materialized view using CDC backfill to restart backfill from the snapshot.
- Verify no crash occurred mid state-commit (check earlier logs); if so, rebuilding state is the safe path.
- Check RisingWave version skew between writer and reader; rebuild state after upgrading.
- Inspect the state table row to confirm cdc_offset is NULL and report as a writer bug if reproducible.
Defensive patterns
Strategy: fallback
Prevention
- Ensure CDC backfill state writes (finished flag + offset) commit together; avoid builds with known partial-write bugs.
- Re-create the CDC table when recovery hits this error rather than forcing the backfill to resume.
- Keep meta/compute versions aligned and upgrade to patched releases before large backfills.
When it happens
Trigger: Recovery of an unfinished CDC backfill whose persisted state row has a NULL `cdc_offset` — state row written without the offset (e.g. partial write or writer bug) while `backfill_finished` is false.
Common situations: Crash between writing `backfill_finished=false` state and persisting the offset, version upgrades altering the encoding, or corrupted state store rows.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid backfill state: row_count
- invalid backfill state: backfill_finished
- ParallelizedCdcBackfillExecutor expects either Mutation::Add
- legacy no-shuffle backfill recovered unfinished progress; ca
- implement MySQL CDC parallelized backfill
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/b194fb21fc9b5cc5.
Report an issue: GitHub.