jdx/mise · error
workspace provider {:?} attributed lockfile {:?} to unknown
Error message
workspace provider {:?} attributed lockfile {:?} to unknown project {id:?} What it means
WorkspaceProjectGraph::affected_projects_for_lockfile() validates that each ID a provider returns is both correctly namespaced AND present in the graph's discovered projects. This variant fires when the namespace is right but the project itself was never discovered — the provider attributed a lockfile to one of its own projects that the graph does not contain.
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 9dcfcaa0dc)
Solutions
- Make the provider only attribute projects it would itself discover (cross-check its own discover() result before returning)
- Rebuild the graph from the same workspace root and provider set used for attribution so discovery and attribution agree
- Strip lockfile-attributed IDs that do not resolve via graph.get() before merging them into lockfile_projects
Example fix
// before (inside a custom provider)
let mut ids = BTreeSet::new();
for name in lockfile_packages { ids.insert(name.parse()?); }
Ok(Some(ids))
// after
let discovered: BTreeSet<ProjectId> = self.discover(root)?.into_iter().map(|p| p.id).collect();
let ids = lockfile_packages.iter().filter_map(|n| n.parse().ok()).filter(|id| discovered.contains(id)).collect();
Ok(Some(ids)) Defensive patterns
Strategy: validation
Validate before calling
// inside a provider: only attribute projects you would discover let discovered: BTreeSet<ProjectId> = self.discover(workspace_root)?.into_iter().map(|p| p.id).collect(); let ids: BTreeSet<ProjectId> = attributed.into_iter().filter(|id| discovered.contains(id)).collect(); Ok((!ids.is_empty()).then_some(ids))
Type guard
fn attribution_is_discoverable(provider: &dyn WorkspaceProvider, root: &Path, ids: &BTreeSet<ProjectId>) -> bool {
let discovered: BTreeSet<ProjectId> = provider.discover(root).map(|ps| ps.into_iter().map(|p| p.id).collect()).unwrap_or_default();
ids.iter().all(|id| discovered.contains(id))
} Try / catch
match graph.affected_projects_for_lockfile(providers, path, before, after) {
Ok(res) => res,
Err(err) if err.to_string().contains("attributed lockfile") => {
warn!("provider attribution out of sync: {err}");
None
}
Err(err) => return Err(err),
} Prevention
- Derive lockfile attribution and discovery from the same manifest-parsing code path
- Regenerate the graph after workspace membership edits before processing lockfile changes
- Filter lockfile-parsed package names through the current discovery result, not raw lockfile contents
When it happens
Trigger: A provider's lockfile attribution reads the lockfile contents (e.g. package names recorded in a lockfile) and returns an ID for a package that discovery skipped: the member is excluded from workspace members, its manifest was filtered out, the project was removed via [monorepo.projects] override, or discovery ran in lenient mode and that provider partially failed.
Common situations: Lockfile still lists a package after it was removed from pnpm-workspace.yaml / Cargo members; monorepo shrink during a refactor; provider attribution logic reading stale lockfile entries ('before'/'after' snapshots spanning a membership change).
Related errors
- lockfile {:?} attributed to unknown workspace project {id:?}
- workspace provider {:?} attributed lockfile {:?} to foreign
- unknown workspace project {id:?}
- workspace project {:?} depends on unknown project {:?}
- removed workspace project {id:?} cannot define other overrid
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/1fe4ea259d15cf71.
Report an issue: GitHub.