{"record":{"id":"a9750157f62f6b7d","repo":"risingwavelabs/risingwave","slug":"duplicate-worker-id-worker-id-in-plan-prev-wor","errorCode":null,"errorMessage":"duplicate worker id {worker_id} in plan, prev {worker_id} -> {dup_change}","messagePattern":"duplicate worker id (.+?) in plan, prev (.+?) -> (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/ctl/src/cmd_impl/meta/reschedule.rs","lineNumber":170,"sourceCode":"        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 });\n        }\n    }\n    Ok(reschedules)\n}\n\npub async fn unregister_workers(\n    context: &CtlContext,\n    workers: Vec<String>,\n    yes: bool,\n    ignore_not_found: bool,\n    check_fragment_occupied: bool,","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/ctl/src/cmd_impl/meta/reschedule.rs#L152-L188","documentation":"parse_plan builds a per-worker actor-count diff; inserting a worker id that already appeared in the plan means the plan tries to change the same worker twice, which is ambiguous, so parsing bails with this message.","triggerScenarios":"A plan string listing the same worker id in two worker-change entries within (or the parse sees duplicates across) fragment sections, e.g. '1:2,1:5'.","commonSituations":"Merging plans from multiple runs without deduplicating workers; hand-editing plans and duplicating a worker entry.","solutions":["Deduplicate worker entries so each worker id appears once per plan","Merge the counts for repeated worker ids into a single entry","Regenerate the plan from the meta tooling, which produces unique worker ids"],"exampleFix":"// before\nfragment 100 [1:2, 1:5]\n// after\nfragment 100 [1:5]","handlingStrategy":"validation","validationCode":"let mut seen = HashSet::new();\nfor w in worker_ids {\n    if !seen.insert(w) {\n        return Err(anyhow!(\"duplicate worker id {}\", w));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate worker entries before building the plan","Generate plans with tooling instead of manual merging"],"tags":["rust","risingwave","reschedule","conflict"],"backgroundTag":"conflicting-config-options","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"}