risingwavelabs/risingwave · error · anyhow::Error

plan "{}" does not have a valid fragment id

Error message

plan "{}" does not have a valid fragment id

What it means

In parse_plan (risectl reschedule), each semicolon-separated segment must match the regex `<fragment_id>:[<worker deltas>]`; if the fragment part cannot be captured, the input plan string is malformed and this error is returned. The input at fault is the `plan` argument that does not follow the `1:[1:+1,2:-1]` format.

Source

Thrown at src/ctl/src/cmd_impl/meta/reschedule.rs:159

// 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}",
                );
            }
        }

        if !worker_actor_diff.is_empty() {
            reschedules.insert(fragment_id, PbWorkerReschedule { worker_actor_diff });

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure each plan section starts with a valid numeric fragment id
  2. Use the correct fragment ids from the meta catalog, not job or worker ids
  3. Regenerate the plan from the cluster rather than editing ids by hand
Defensive patterns

Strategy: validation

Validate before calling

if !fragment_id_str.chars().all(|c| c.is_ascii_digit()) || fragment_id_str.is_empty() {
    return Err(anyhow!("fragment id must be numeric"));
}

Prevention

When it happens

Trigger: A plan section whose first captured group is non-numeric or absent (e.g. 'abc [1:3]' or an empty fragment id).

Common situations: Corrupted or hand-modified plan text; using a table/job id where a fragment id is expected.

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


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