risingwavelabs/risingwave · error

actor count ( ) exceeds vnode count ( )

Error message

actor count ({}) exceeds vnode count ({})

What it means

`assign_hierarchical` validates that the number of actors does not exceed the number of virtual nodes, since every actor needs at least one vnode. When `actors.len() > virtual_nodes.len()`, balanced per-actor assignment is impossible and the function returns this descriptive error.

Solutions

  1. Increase the vnode count to at least the actor count (RisingWave default is 256).
  2. Reduce fragment parallelism so actors.len() <= vnodes.len().
  3. When calling the API directly, always derive vnode count from the same config as parallelism instead of hardcoding.

Example fix

// before
let vnodes: Vec<u32> = (0..2).collect();
let mapping = assign_hierarchical(&workers, &actors, &vnodes, strategy)?; // 4 actors
// after
let vnodes: Vec<u32> = (0..256).collect();
let mapping = assign_hierarchical(&workers, &actors, &vnodes, strategy)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust, before calling assignment
if actors.len() > vnodes.len() {
    anyhow::bail!("need at least {} vnodes, have {}", actors.len(), vnodes.len());
}

Try / catch

match assign_hierarchical(&workers, &actors, &vnodes, strategy) {
    Ok(m) => m,
    Err(e) if e.to_string().contains("exceeds vnode count") => {
        Err(anyhow!("increase vnode count or reduce parallelism: {e:#}"))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling `assign_hierarchical` (assignment.rs:406) with more actor ids than vnode ids; test `error_when_more_actors_than_vnodes` exercises this.

Common situations: Manually constructing a tiny vnode set (e.g. 2 vnodes) while creating more actors (e.g. 4-way parallelism); test/tooling misuse of the generic API; a vnode-count override below the fragment's parallelism.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/d87ab14f55ba73fc. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/src/stream/stream_graph/assignment.rs:406

    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,
    };

    // Distribute actors across workers based on their weight
    let actor_to_worker: BTreeMap<W, Vec<A>> =
        assign_items_weighted_with_scale_fn(workers, actors, salt, actor_capacity_fn);

    // Build unit-weight map for active workers (those with assigned actors)
    let mut active_worker_weights: BTreeMap<W, NonZeroUsize> = BTreeMap::new();

View on GitHub (pinned to 6469eb736d)