jdx/mise · error
workspace provider {:?} attributed lockfile {:?} to foreign
Error message
workspace provider {:?} attributed lockfile {:?} to foreign project {id:?} What it means
When WorkspaceProjectGraph::affected_projects_for_lockfile() asks each WorkspaceProvider to attribute a changed lockfile, every returned ProjectId must live in that provider's own namespace: it must start with "{provider.id()}:". This error means a provider returned an ID carrying a different (foreign) prefix, which would let one provider's attribution mutate another provider's projects.
Source
Thrown at src/task/workspace.rs:964
lockfile_path: &Path,
before: Option<&str>,
after: Option<&str>,
) -> Result<Option<BTreeSet<ProjectId>>> {
let mut providers = providers.to_vec();
providers.sort_by(|left, right| left.id().cmp(right.id()));
let mut recognized = false;
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))
}
View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Construct every returned ID with ProjectId::new(self.id(), local_id) so the prefix can never drift
- If the provider changes or the code was adapted, re-run attribution and assert id.as_str().starts_with(&format!("{}:", self.id())) in tests
- Return None (lockfile not recognized) instead of attributing to projects owned by other providers
Example fix
// before (custom provider)
fn affected_projects_for_lockfile(...) -> Result<Option<BTreeSet<ProjectId>>> {
Ok(Some(BTreeSet::from(["cargo:app".parse()?]))) // foreign namespace
}
// after
fn affected_projects_for_lockfile(...) -> Result<Option<BTreeSet<ProjectId>>> {
Ok(Some(BTreeSet::from([ProjectId::new(self.id(), "app")?])))
} Defensive patterns
Strategy: validation
Validate before calling
let prefix = format!("{}:", self.id());
let ids: BTreeSet<ProjectId> = candidates
.into_iter()
.filter(|id| id.as_str().starts_with(&prefix))
.collect();
Ok(Some(ids)) Type guard
fn in_own_namespace(provider_id: &str, id: &ProjectId) -> bool {
id.as_str().starts_with(&format!("{provider_id}:"))
} Prevention
- Never hand-format provider project IDs; always use ProjectId::new(self.id(), local)
- Add a unit test asserting every ID returned by affected_projects_for_lockfile starts with your provider prefix
- If your provider cannot attribute a lockfile confidently, return Ok(None) rather than borrowing another provider's IDs
When it happens
Trigger: Implementing a custom WorkspaceProvider whose affected_projects_for_lockfile returns IDs like "cargo:some-crate" while provider.id() returns e.g. "myprov"; hand-formatting IDs (format!("{}:{}", wrong_ns, local)) instead of constructing them with ProjectId::new(self.id(), local); copy-pasting another provider's attribution logic without changing the namespace.
Common situations: Writing a first-party workspace provider for an in-house build system; adapting the node.rs provider sample; provider id() renamed but attribution code still returns IDs under the old namespace.
Related errors
- workspace provider {:?} attributed lockfile {:?} to unknown
- unknown workspace project {id:?}
- lockfile {:?} attributed to 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/4eb0081f6ee9c03c.
Report an issue: GitHub.