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

  1. Check the CDC streaming job status (SHOW JOBS / job state); if it was dropped or finishing, this is a benign race — retry or ignore.
  2. Ensure worker nodes are healthy so actors can be scheduled before splits are reassigned (check compute node liveness and actor counts).
  3. Retry the operation; reassign_splits is typically triggered again by the scheduler once actors exist.
  4. 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

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


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)