risingwavelabs/risingwave · error
Expect at least 1 CDC table snapshot splits, 0 was found.
Error message
Expect at least 1 CDC table snapshot splits, 0 was found.
What it means
The mirror-side guard of assign_cdc_table_snapshot_splits: it rejects when the snapshot split list is empty, since there is nothing to distribute to the actors. Raised when reassign_splits reloads splits for a CDC table and finds zero pending snapshot splits despite actors being available.
Solutions
- Verify the CDC table's snapshot backfill state; if already complete, no snapshot reassignment is needed — the error is a benign race and can be retried/ignored.
- Check the split rows for the job in the meta store; if splits were removed unexpectedly, restore from backup or recreate the CDC table.
- Retry the operation; the scheduler should skip snapshot reassignment once backfill is finished.
- If persistent with pending splits missing, recreate the CDC table's backfill.
Defensive patterns
Strategy: validation
Validate before calling
let pending: Vec<_> = load_splits_for_job(job_id).await?;
let snapshot_splits: Vec<_> = pending.into_iter().filter(|s| s.is_snapshot()).collect();
if !snapshot_splits.is_empty() {
assign_cdc_table_snapshot_splits(actors, &snapshot_splits, generation)?;
} Try / catch
match reassign_splits(job_id).await {
Err(e) if e.to_string().contains("Expect at least 1 CDC table snapshot splits") => {
// snapshot backfill likely already completed; log and continue
tracing::debug!(%job_id, "no snapshot splits left to assign");
}
other => other?,
} Prevention
- Check backfill completion state before reassigning snapshot splits.
- Filter split lists to snapshot splits only before calling assignment.
- Treat concurrent backfill-completion races as benign and retry.
When it happens
Trigger: reassign_splits calls assign_cdc_table_snapshot_splits with a non-empty actor set but an empty slices of CdcTableSnapshotSplitRaw — e.g. all snapshot splits were already assigned/completed but a reschedule still requested snapshot reassignment, or the meta store returned no splits for the table.
Common situations: Backfill already finished when a recovery/scale event triggers reassignment; concurrent completion of splits by another meta operation; race between backfill completion and reschedule.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Expect at least 1 actor, 0 was found.
- implement MySQL CDC parallelized backfill
- implement SqlServer CDC parallelized backfill
- invalid backfill state: backfill_finished
- invalid backfill state: row_count
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/6816a6d4638b5e80.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/stream/cdc.rs:199
assert_eq!(
stream_scan_fragments.count(),
0,
"Expect no remaining scan fragment",
);
Some(fragment)
}
pub(crate) fn assign_cdc_table_snapshot_splits(
actor_ids: HashSet<ActorId>,
splits: &[CdcTableSnapshotSplitRaw],
generation: u64,
) -> MetaResult<HashMap<ActorId, PbCdcTableSnapshotSplits>> {
if actor_ids.is_empty() {
return Err(anyhow::anyhow!("Expect at least 1 actor, 0 was found.").into());
}
if splits.is_empty() {
return Err(
anyhow::anyhow!("Expect at least 1 CDC table snapshot splits, 0 was found.").into(),
);
}
let splits_per_actor = splits.len().div_ceil(actor_ids.len());
let mut assignments = HashMap::new();
for (actor_id, splits) in actor_ids.iter().copied().zip_eq_debug(
splits
.iter()
.map(build_cdc_table_snapshot_split)
.chunks(splits_per_actor)
.into_iter()
.map(|c| c.collect_vec())
.chain(iter::repeat(Vec::default()))
.take(actor_ids.len()),
) {
assignments.insert(actor_id, PbCdcTableSnapshotSplits { splits, generation });
}
Ok(assignments)
}View on GitHub (pinned to 6469eb736d)