{"record":{"id":"38e745aa35ff2192","repo":"risingwavelabs/risingwave","slug":"plan-does-not-have-a-valid-fragment-id","errorCode":null,"errorMessage":"plan \"{}\" does not have a valid fragment id","messagePattern":"plan \"(.+?)\" does not have a valid fragment id","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/ctl/src/cmd_impl/meta/reschedule.rs","lineNumber":159,"sourceCode":"// 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.\nfn parse_plan(mut plan: String) -> Result<HashMap<u32, PbWorkerReschedule>> {\n    let mut reschedules = HashMap::new();\n    let regex = Regex::new(r\"^(\\d+):\\[((?:\\d+:[+-]?\\d+,?)+)]$\")?;\n    plan.retain(|c| !c.is_whitespace());\n\n    for fragment_reschedule_plan in plan.split(';') {\n        if fragment_reschedule_plan.is_empty() {\n            continue;\n        }\n\n        let captures = regex\n            .captures(fragment_reschedule_plan)\n            .ok_or_else(|| anyhow!(\"plan \\\"{}\\\" format illegal\", fragment_reschedule_plan))?;\n\n        let fragment_id = captures\n            .get(1)\n            .and_then(|mat| mat.as_str().parse::<u32>().ok())\n            .ok_or_else(|| anyhow!(\"plan \\\"{}\\\" does not have a valid fragment id\", plan))?;\n\n        let worker_changes: Vec<&str> = captures[2].split(',').collect();\n\n        let mut worker_actor_diff = HashMap::new();\n        for worker_change in &worker_changes {\n            let (worker_id, count) = worker_change.split(':').collect_tuple::<(_, _)>().unwrap();\n            let worker_id = worker_id.parse().unwrap();\n            let count = count.parse().unwrap();\n\n            if let Some(dup_change) = worker_actor_diff.insert(worker_id, count) {\n                anyhow::bail!(\n                    \"duplicate worker id {worker_id} in plan, prev {worker_id} -> {dup_change}\",\n                );\n            }\n        }\n\n        if !worker_actor_diff.is_empty() {\n            reschedules.insert(fragment_id, PbWorkerReschedule { worker_actor_diff });","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/ctl/src/cmd_impl/meta/reschedule.rs#L141-L177","documentation":"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.","triggerScenarios":"A plan section whose first captured group is non-numeric or absent (e.g. 'abc [1:3]' or an empty fragment id).","commonSituations":"Corrupted or hand-modified plan text; using a table/job id where a fragment id is expected.","solutions":["Ensure each plan section starts with a valid numeric fragment id","Use the correct fragment ids from the meta catalog, not job or worker ids","Regenerate the plan from the cluster rather than editing ids by hand"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if !fragment_id_str.chars().all(|c| c.is_ascii_digit()) || fragment_id_str.is_empty() {\n    return Err(anyhow!(\"fragment id must be numeric\"));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify fragment ids from the meta catalog","Do not substitute table or worker ids for fragment ids"],"tags":["rust","risingwave","parsing","invalid-value"],"backgroundTag":"invalid-argument-format","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}