risingwavelabs/risingwave · error
no actors to assign
Error message
no actors to assign
What it means
The generic `assign_hierarchical` worker/actor/vnode assignment function requires at least one actor to distribute; an empty actor list makes the assignment meaningless. It fails fast at the top of the function before any distribution work.
Source
Thrown at src/meta/src/stream/stream_graph/assignment.rs:397
/// - For each worker, take its vnode list and assign them to actors in simple round-robin:
/// iterate vnodes in order, dispatching index `% actor_list.len()`.
/// - Collect into final `BTreeMap<W, BTreeMap<A, Vec<V>>>`.
pub fn assign_hierarchical<W, A, V, S>(
workers: &BTreeMap<W, NonZeroUsize>,
actors: &[A],
virtual_nodes: &[V],
salt: S,
actor_capacity_mode: CapacityMode,
balanced_by: BalancedBy,
) -> anyhow::Result<BTreeMap<W, BTreeMap<A, Vec<V>>>>
where
W: Ord + Hash + Eq + Clone + Debug,
A: Ord + Hash + Eq + Copy + Clone + Debug,
V: Hash + Eq + Copy + Clone + Debug,
S: Hash + Copy,
{
if actors.is_empty() {
return Err(anyhow!("no actors to assign"));
}
if virtual_nodes.is_empty() {
return Err(anyhow!("no vnodes to assign"));
}
// Validate input: ensure vnode count can cover all actors
if actors.len() > virtual_nodes.len() {
return Err(anyhow!(
"actor count ({}) exceeds vnode count ({})",
actors.len(),
virtual_nodes.len()
));
}
let actor_capacity_fn = match actor_capacity_mode {
CapacityMode::Weighted => weighted_scale,
CapacityMode::Unbounded => unbounded_scale,View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure the fragment graph has generated actors (parallelism >= 1) before calling assignment.
- Guard the caller: skip assignment or return a domain error when `actors.is_empty()`.
- Check why upstream rewrite produced zero actors for the fragment (e.g. disabled fragments) and fix plan generation.
Example fix
// before
let mapping = assign_hierarchical(&workers, &[], &vnodes, strategy)?;
// after
if actors.is_empty() {
anyhow::bail!("fragment has no actors to assign");
}
let mapping = assign_hierarchical(&workers, &actors, &vnodes, strategy)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust, before calling assignment
if actors.is_empty() {
anyhow::bail!("refusing to assign: actor list is empty");
} Type guard
fn non_empty<'a, T>(xs: &'a [T]) -> Option<&'a [T]> {
if xs.is_empty() { None } else { Some(xs) }
} Try / catch
match assign_hierarchical(&workers, &actors, &vnodes, strategy) {
Ok(mapping) => mapping,
Err(e) if e.to_string().contains("no actors to assign") => {
tracing::warn!("skipping assignment: no actors generated");
BTreeMap::new()
}
Err(e) => return Err(e),
} Prevention
- Always generate actors (parallelism >= 1) before scheduling.
- Validate fragment outputs in plan generation tests.
- Filter degenerate zero-actor fragments upstream with explicit errors.
When it happens
Trigger: Calling `assign_hierarchical` (assignment.rs:397) with `actors.is_empty() == true`; tests `error_on_empty_actors` exercise this directly.
Common situations: Building/assigning a stream fragment whose actor set was not generated (e.g. a degenerate fragment with zero parallelism); calling the assignment API in tests or tools with an empty actor vector; upstream bug that filtered out all actors before assignment.
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
- no vnodes to assign
- no actors to assign; assignment is meaningless
- actor count ({}) exceeds vnode count ({})
- no workers to assign; assignment is meaningless
- no vnodes to assign; assignment is meaningless
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/a8ac186b1d2c4e3f.
Report an issue: GitHub.