jdx/mise · error
workspace provider attributed lockfile to unknown project
Error message
workspace provider {:?} attributed lockfile {:?} to unknown project {id:?} What it means
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.
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
Example fix
// before
let id = format!("{}:{}", self.id(), dir_name);
attribution.insert(lockfile, id);
// after
if let Some(p) = self.discovered.iter().find(|p| p.root == dir) {
attribution.insert(lockfile, p.id.clone());
} Defensive patterns
Strategy: validation
Validate before calling
for id in &ids {
if !workspace.projects.contains_key(id) {
eprintln!("skipping lockfile attribution to missing project {id}");
}
} Type guard
fn is_known_project<'a>(ws: &Workspace, id: &'a str) -> bool { ws.projects.contains_key(id) } Try / catch
match attribute(lockfile, ids) {
Ok(_) => (),
Err(e) if e.to_string().contains("unknown project") => {
eprintln!("lockfile references removed/renamed project; clean up or rediscover");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- lockfile attributed to unknown workspace project
- workspace provider attributed lockfile to foreign project
- duplicate workspace provider ID
- pnpm lockfile dependency
- pnpm lockfile dependency
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/1fe4ea259d15cf71.
Report an issue: GitHub.
Appendix: source
Thrown at src/task/workspace.rs:971
let mut affected = BTreeSet::new();
for provider in providers {
let Some(projects) =
provider.affected_projects_for_lockfile(lockfile_path, before, after, self)?
else {
continue;
};
recognized = true;
let expected_prefix = format!("{}:", provider.id());
for id in projects {
if !id.as_str().starts_with(&expected_prefix) {
bail!(
"workspace provider {:?} attributed lockfile {:?} to foreign project {id:?}",
provider.id(),
lockfile_path
);
}
if !self.projects.contains_key(&id) {
bail!(
"workspace provider {:?} attributed lockfile {:?} to unknown project {id:?}",
provider.id(),
lockfile_path
);
}
affected.insert(id);
}
}
Ok(recognized.then_some(affected))
}
/// Summarizes provider failures retained during lenient task discovery.
pub(crate) fn provider_discovery_error(&self) -> Option<String> {
(!self.provider_errors.is_empty()).then(|| {
self.provider_errors
.iter()
.map(|(provider, error)| format!("{provider}: {error}"))
.collect::<Vec<_>>()View on GitHub (pinned to 533346cc37)