risingwavelabs/risingwave · error · anyhow::Error
plan "{}" format illegal
Error message
plan "{}" format illegal What it means
parse_plan splits the reschedule plan into per-fragment strings and matches each against a regex to extract fragment id and worker changes. This error means a fragment plan chunk did not match the expected format, so it cannot be parsed.
Source
Thrown at src/ctl/src/cmd_impl/meta/reschedule.rs:154
}
Ok(())
}
// It will match formats like `1:[1:+1,2:-1,3:1];2:[1:1,2:1]`, indicating which workers' actors need to change in quantity for each fragment.
fn parse_plan(mut plan: String) -> Result<HashMap<u32, PbWorkerReschedule>> {
let mut reschedules = HashMap::new();
let regex = Regex::new(r"^(\d+):\[((?:\d+:[+-]?\d+,?)+)]$")?;
plan.retain(|c| !c.is_whitespace());
for fragment_reschedule_plan in plan.split(';') {
if fragment_reschedule_plan.is_empty() {
continue;
}
let captures = regex
.captures(fragment_reschedule_plan)
.ok_or_else(|| anyhow!("plan \"{}\" format illegal", fragment_reschedule_plan))?;
let fragment_id = captures
.get(1)
.and_then(|mat| mat.as_str().parse::<u32>().ok())
.ok_or_else(|| anyhow!("plan \"{}\" does not have a valid fragment id", plan))?;
let worker_changes: Vec<&str> = captures[2].split(',').collect();
let mut worker_actor_diff = HashMap::new();
for worker_change in &worker_changes {
let (worker_id, count) = worker_change.split(':').collect_tuple::<(_, _)>().unwrap();
let worker_id = worker_id.parse().unwrap();
let count = count.parse().unwrap();
if let Some(dup_change) = worker_actor_diff.insert(worker_id, count) {
anyhow::bail!(
"duplicate worker id {worker_id} in plan, prev {worker_id} -> {dup_change}",
);View on GitHub (pinned to 6469eb736d)
Solutions
- Reformat the plan to the expected per-fragment syntax the regex expects
- Copy the plan directly from the meta tooling output instead of retyping it
- Match risectl and meta versions so plan formats agree
Defensive patterns
Strategy: validation
Validate before calling
if !plan.lines().all(|l| l.trim().is_empty() || FRAGMENT_RE.is_match(l.trim())) {
return Err(anyhow!("plan lines must match fragment plan format"));
} Prevention
- Copy plans verbatim from meta output
- Avoid hand-editing plan text
- Keep risectl and meta node versions in sync
When it happens
Trigger: Passing a reschedule plan string whose fragment sections deviate from the expected pattern (missing brackets, wrong separators, whitespace or extra text where the regex expects 'fragment_id [worker:count,...]').
Common situations: Hand-editing plan text copied from meta logs; older/newer plan formats from mismatched risectl and meta versions; truncation when pasting multi-line plans.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- plan "{}" does not have a valid fragment id
- Invalid time: {value} {unit} is out of range for a time of d
- Can't cast string to date (expected format is YYYY-MM-DD)
- Can't cast string to time (expected format is HH:MM:SS[.D+{u
- Can't cast string to timestamp (expected format is YYYY-MM-D
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/04c25d6dcec46c1f.
Report an issue: GitHub.