risingwavelabs/risingwave · error
not enough vnodes ({}) for actors ({}); each actor needs at
Error message
not enough vnodes ({}) for actors ({}); each actor needs at least one vnode What it means
The last guard in the ensure! chain (assignment.rs:761) requires `vnodes.len() >= actors.len()` because each actor must receive at least one virtual node. When there are fewer vnodes than actors, a valid per-actor vnode set cannot be constructed and the function errors with both counts.
Source
Thrown at src/meta/src/stream/stream_graph/assignment.rs:761
) -> Result<BTreeMap<W, BTreeMap<A, Vec<V>>>>
where
W: Ord + Hash + Eq + Clone + Debug,
A: Ord + Hash + Eq + Copy + Debug,
V: Hash + Eq + Copy + Debug,
{
ensure!(
!workers.is_empty(),
"no workers to assign; assignment is meaningless"
);
ensure!(
!actors.is_empty(),
"no actors to assign; assignment is meaningless"
);
ensure!(
!vnodes.is_empty(),
"no vnodes to assign; assignment is meaningless"
);
ensure!(
vnodes.len() >= actors.len(),
"not enough vnodes ({}) for actors ({}); each actor needs at least one vnode",
vnodes.len(),
actors.len()
);
let chunk_size = match self.vnode_chunking_strategy {
VnodeChunkingStrategy::NoChunking => {
return assign_hierarchical(
workers,
actors,
vnodes,
self.salt,
self.actor_capacity,
self.balance_strategy,
)
.context("hierarchical assignment failed");
}View on GitHub (pinned to 6469eb736d)
Solutions
- Set vnode count to at least the actor count (RisingWave default 256 covers typical parallelism).
- Lower the fragment parallelism to fit within the vnode count.
- When computing vnodes programmatically, derive the size as `max(default, parallelism)`.
Example fix
// before let vnodes: Vec<u32> = (0..2).collect(); // 4 actors // after let vnodes: Vec<u32> = (0..actors.len().max(DEFAULT_VNODE_COUNT)).collect();
Defensive patterns
Strategy: validation
Validate before calling
// Rust, before scheduling
if vnodes.len() < actors.len() {
anyhow::bail!("vnodes ({}) < actors ({})", vnodes.len(), actors.len());
} Try / catch
match assign_hierarchical(&workers, &actors, &vnodes, strategy) {
Ok(m) => m,
Err(e) if e.to_string().contains("not enough vnodes") => {
Err(anyhow!("raise vnode count above parallelism: {e:#}"))
}
Err(e) => Err(e),
} Prevention
- Size vnode sets as max(default_vnode_count, parallelism).
- Validate vnode-count overrides against parallelism at config load time.
- Add a property test: assignment succeeds whenever vnodes >= actors.
When it happens
Trigger: Calling the inner `assign_hierarchical` where `vnodes.len() < actors.len()` — e.g. 4 actors but 2 vnodes.
Common situations: Custom vnode-count settings lower than fragment parallelism; test/tooling calls with shrunken vnode sets; vnode count overridden by a config that ignores parallelism.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- actor count ({}) exceeds vnode count ({})
- no actors to assign
- no vnodes to assign
- no actors 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/9415889d4703cc59.
Report an issue: GitHub.