risingwavelabs/risingwave · error
Expect at least 1 actor, 0 was found.
Error message
Expect at least 1 actor, 0 was found.
What it means
assign_cdc_table_snapshot_splits distributes CDC table snapshot splits across a set of actors. It refuses to proceed when the actor set is empty, because there is nowhere to assign splits. reassign_splits raises this when the meta node computed no eligible actors for a CDC table backfill.
Solutions
- Check the CDC streaming job status (SHOW JOBS / job state); if it was dropped or finishing, this is a benign race — retry or ignore.
- Ensure worker nodes are healthy so actors can be scheduled before splits are reassigned (check compute node liveness and actor counts).
- Retry the operation; reassign_splits is typically triggered again by the scheduler once actors exist.
- If persistent, restart the affected compute node or recreate the CDC table backfill.
Defensive patterns
Strategy: validation
Validate before calling
let actors: Vec<_> = job.actors.values().filter(|a| a.is_running()).collect();
if actors.is_empty() {
// skip snapshot reassignment until actors exist
return Ok(());
} Try / catch
match reassign_splits(job_id).await {
Err(e) if e.to_string().contains("Expect at least 1 actor") => {
// benign: job likely dropped or finishing; log and skip
tracing::debug!(%job_id, "no actors for cdc snapshot reassignment");
}
other => other?,
} Prevention
- Keep enough healthy compute nodes so CDC backfill actors can always be scheduled.
- Check job state (dropped/finishing) before requesting snapshot reassignment.
- Retry reassignment after worker recovery instead of failing the whole job.
When it happens
Trigger: reassign_splits calls assign_cdc_table_snapshot_splits with an empty actor_ids HashSet — e.g. all actors for the CDC table were removed, the streaming job has no running actors, or actor filtering (by state/host) eliminated every candidate during recovery or scale-in.
Common situations: Rescheduling after a worker node failure where no replacement actor was created yet; interrupting a CDC backfill mid-flight; recovering a CDC job whose fragments were already dropped in meta.
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 CDC table snapshot splits, 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/c55355a91b5b8ce6.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/stream/cdc.rs:195
is_parallelized_backfill_enabled_cdc_scan_fragment(f.fragment_type_mask, &f.nodes)
.map(|cdc_scan| (f, cdc_scan))
});
let fragment = stream_scan_fragments.next()?;
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()),
) {View on GitHub (pinned to 6469eb736d)