{"record":{"id":"048640f364ccd981","repo":"jdx/mise","slug":"workspace-provider-provider-id-returned-duplic","errorCode":null,"errorMessage":"workspace provider {provider_id:?} returned duplicate project ID {id:?}","messagePattern":"workspace provider (.+?) returned duplicate project ID (.+?)","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/task/workspace.rs","lineNumber":664,"sourceCode":"                    provider_errors.insert(provider_id, error);\n                    continue;\n                }\n                Err(error) => return Err(error),\n            };\n            for mut project in discovered {\n                let expected_prefix = format!(\"{provider_id}:\");\n                let Some(local_id) = project.id.as_str().strip_prefix(&expected_prefix) else {\n                    bail!(\n                        \"workspace provider {provider_id:?} returned project ID {:?}; IDs must use the {expected_prefix:?} namespace\",\n                        project.id\n                    );\n                };\n                validate_id_part(\"project\", local_id)?;\n                project.root = normalize_project_root(&project.id, &project.root)?;\n                attach_provider_provenance(&mut project, &provider_id);\n                let id = project.id.clone();\n                if projects.insert(id.clone(), project).is_some() {\n                    bail!(\n                        \"workspace provider {provider_id:?} returned duplicate project ID {id:?}\"\n                    );\n                }\n            }\n        }\n\n        Ok(Self {\n            projects,\n            provider_errors,\n        })\n    }\n\n    /// Applies explicit project and dependency changes after provider discovery.\n    pub(crate) fn with_overrides(\n        mut self,\n        overrides: &BTreeMap<String, WorkspaceProjectOverride>,\n    ) -> Result<Self> {\n        let mut removed = BTreeSet::new();","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/task/workspace.rs#L646-L682","documentation":"While folding provider results into WorkspaceProjectGraph, each discovered project is inserted into a map keyed by its full ProjectId; if the same id is already present the second insert fails with this error. It means a single provider returned two distinct projects whose ecosystem-level identity (package name, module path) collides within one provider namespace.","triggerScenarios":"Two crates in one Cargo workspace declaring the same [package] name (both matched by the members glob); two directories in a go.work use list whose go.mod files declare the same module path; a leftover old directory plus its renamed copy both matching \"crates/*\" members.","commonSituations":"Copy-pasted crate scaffolding that kept the original package name; a monorepo refactor that renamed a directory but not its module path; vendored forks with duplicate module paths; merging two workspaces together.","solutions":["Rename one of the colliding packages (Cargo.toml [package] name) or module paths (go.mod module directive) so ids become unique","If one copy is dead code, exclude its directory from Cargo [workspace] members/exclude or drop it from go.work use","Run `cargo metadata` or `go work sync` first to confirm the toolchain itself also sees the duplicate","If both projects are legitimately distinct, give the second one a distinct ecosystem name rather than trying to alias the id"],"exampleFix":"# before: crates/old-core/Cargo.toml and crates/new-core/Cargo.toml both have\n[package]\nname = \"core\"\n\n# after (crates/new-core/Cargo.toml)\n[package]\nname = \"new-core\"\n# update any [monorepo.projects.\"cargo:core\"] override key to \"cargo:new-core\"","handlingStrategy":"try-catch","validationCode":"let mut seen = std::collections::BTreeSet::new();\nfor project in provider.discover(root)? {\n    if !seen.insert(project.id.as_str().to_string()) {\n        // two ecosystem entries share this id; rename one before building the graph\n        return Err(eyre::eyre!(\"duplicate id {} discovered\", project.id));\n    }\n}","typeGuard":"fn has_unique_ids(projects: &[WorkspaceProject]) -> bool {\n    let mut seen = std::collections::BTreeSet::new();\n    projects.iter().all(|p| seen.insert(p.id.as_str().to_string()))\n}","tryCatchPattern":"// after catching the eyre::Report from graph construction:\nlet msg = report.to_string();\nif msg.contains(\"duplicate project ID\") {\n    // extract the id and point the user at the two same-named packages/modules\n    report_project_duplicate(&msg);\n}","preventionTips":["Enforce unique package names / module paths in monorepo lint rules","Run `cargo metadata --no-deps` or `go work sync` in CI; both fail on duplicate identities","When scaffolding a new crate or module, always rename the copied package name / module path immediately"],"tags":["workspace","duplicate","cargo","go","provider","rust"],"backgroundTag":"duplicate-key","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}