{"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":null,"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/533346cc374382b41ec5ff70536252b2e96e725c/src/task/workspace.rs#L646-L682","documentation":"Projects are collected into a `BTreeMap` keyed by ID; inserting an ID that already exists means two projects collide, so the collector bails. Within one provider, a provider should never return the same project ID twice, and this check enforces that per provider.","triggerScenarios":"A single provider's `collect_provider_projects` returns two projects with identical `id` fields (e.g. the same project discovered via two metadata files, or a loop building duplicate entries).","commonSituations":"A provider scanning directories that matches the same package via both a lockfile and a manifest; symlinked directories visited twice; case-insensitive filesystems where two spellings collapse to one ID.","solutions":["Deduplicate discovered projects inside the provider before returning them","Skip already-seen IDs when scanning (track a visited set by canonical path)","Fix the provider scan so each project is emitted exactly once"],"exampleFix":"// before\nfor dir in dirs {\n    discovered.push(make_project(dir));\n}\n// after\nlet mut seen = HashSet::new();\nfor dir in dirs {\n    let p = make_project(dir);\n    if seen.insert(p.id.clone()) {\n        discovered.push(p);\n    }\n}","handlingStrategy":"validation","validationCode":"let mut seen = std::collections::HashSet::new();\ndiscovered.retain(|p| seen.insert(p.id.clone()));","typeGuard":null,"tryCatchPattern":"match collect_projects(provider) {\n    Ok(ps) => ps,\n    Err(e) if e.to_string().contains(\"duplicate project ID\") => {\n        eprintln!(\"provider emitted the same project twice; dedupe before returning\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Track visited canonical paths when scanning directories for projects","Deduplicate by project ID inside the provider before returning","Beware symlinks and case-insensitive filesystems causing double discovery"],"tags":["workspace","duplicate","provider"],"backgroundTag":"internal-invariant-violation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}