{"record":{"id":"1fe4ea259d15cf71","repo":"jdx/mise","slug":"workspace-provider-attributed-lockfile-t-1fe4ea","errorCode":null,"errorMessage":"workspace provider {:?} attributed lockfile {:?} to unknown project {id:?}","messagePattern":"workspace provider (.+?) attributed lockfile (.+?) to unknown project (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/workspace.rs","lineNumber":971,"sourceCode":"        let mut affected = BTreeSet::new();\n        for provider in providers {\n            let Some(projects) =\n                provider.affected_projects_for_lockfile(lockfile_path, before, after, self)?\n            else {\n                continue;\n            };\n            recognized = true;\n            let expected_prefix = format!(\"{}:\", provider.id());\n            for id in projects {\n                if !id.as_str().starts_with(&expected_prefix) {\n                    bail!(\n                        \"workspace provider {:?} attributed lockfile {:?} to foreign project {id:?}\",\n                        provider.id(),\n                        lockfile_path\n                    );\n                }\n                if !self.projects.contains_key(&id) {\n                    bail!(\n                        \"workspace provider {:?} attributed lockfile {:?} to unknown project {id:?}\",\n                        provider.id(),\n                        lockfile_path\n                    );\n                }\n                affected.insert(id);\n            }\n        }\n        Ok(recognized.then_some(affected))\n    }\n\n    /// Summarizes provider failures retained during lenient task discovery.\n    pub(crate) fn provider_discovery_error(&self) -> Option<String> {\n        (!self.provider_errors.is_empty()).then(|| {\n            self.provider_errors\n                .iter()\n                .map(|(provider, error)| format!(\"{provider}: {error}\"))\n                .collect::<Vec<_>>()","sourceCodeStart":953,"sourceCodeEnd":989,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/task/workspace.rs#L953-L989","documentation":"After confirming a lockfile attribution is in the provider's own namespace, the collector verifies each project ID actually exists in the workspace. If the provider attributes a lockfile to a namespaced-but-unknown project, this error fires, preventing lockfiles from being associated with nonexistent projects.","triggerScenarios":"A provider maps a lockfile to a project ID that discovery did not produce — e.g. the project directory was deleted, the project's local ID changed, or the provider derives the ID from a path that no longer matches discovery.","commonSituations":"Stale lockfile after a project rename (local part of the ID changed); a project excluded from config but its lockfile still present; race where discovery and lockfile scanning see different directory states.","solutions":["Remove the stale lockfile or recreate the missing project","Re-run workspace discovery before lockfile attribution so the project map is fresh","Fix the provider to derive lockfile→project IDs from the current discovered project list rather than from disk paths alone"],"exampleFix":"// before\nlet id = format!(\"{}:{}\", self.id(), dir_name);\nattribution.insert(lockfile, id);\n// after\nif let Some(p) = self.discovered.iter().find(|p| p.root == dir) {\n    attribution.insert(lockfile, p.id.clone());\n}","handlingStrategy":"validation","validationCode":"for id in &ids {\n    if !workspace.projects.contains_key(id) {\n        eprintln!(\"skipping lockfile attribution to missing project {id}\");\n    }\n}","typeGuard":"fn is_known_project<'a>(ws: &Workspace, id: &'a str) -> bool { ws.projects.contains_key(id) }","tryCatchPattern":"match attribute(lockfile, ids) {\n    Ok(_) => (),\n    Err(e) if e.to_string().contains(\"unknown project\") => {\n        eprintln!(\"lockfile references removed/renamed project; clean up or rediscover\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Delete stale lockfiles after project renames or removals","Derive lockfile→project mappings from the current discovery result, not raw directory names","Rediscover the workspace before each lockfile scan"],"tags":["workspace","lockfile","not-found","provider"],"backgroundTag":"entity-not-found","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"}