jdx/mise · error
workspace project {id:?} has absolute root {root:?}; roots m
Error message
workspace project {id:?} has absolute root {root:?}; roots must be workspace-relative What it means
normalize_project_root() converts the root of a [monorepo.projects."<id>"] override (or a provider-supplied root) into a canonical workspace-relative path. The first rule is that the root must be relative: an absolute path (one where Path::is_absolute() is true, e.g. "/home/me/repo/crates/a") is rejected immediately because project roots are stored relative to the workspace root so the graph stays portable and cacheable.
Source
Thrown at src/task/workspace.rs:1190
project_id: &ProjectId,
field: &str,
dependencies: &BTreeSet<String>,
) -> Result<BTreeSet<ProjectId>> {
dependencies
.iter()
.map(|dependency| {
dependency.parse::<ProjectId>().map_err(|err| {
eyre::eyre!(
"workspace project {project_id:?} has invalid {field} entry {dependency:?}: {err}"
)
})
})
.collect()
}
fn normalize_project_root(id: &ProjectId, root: &Path) -> Result<PathBuf> {
if root.is_absolute() {
bail!(
"workspace project {id:?} has absolute root {root:?}; roots must be workspace-relative"
);
}
let mut normalized = PathBuf::new();
for component in root.components() {
match component {
Component::CurDir => {}
Component::Normal(component) => normalized.push(component),
Component::ParentDir => {
if !normalized.pop() {
bail!(
"workspace project {id:?} has root {root:?} that escapes the workspace root"
);
}
}
Component::RootDir | Component::Prefix(_) => {
bail!(View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Express the root relative to the workspace root: root = "crates/a"
- If tooling generates the entry, strip the workspace-root prefix (path.strip_prefix(workspace_root)) before writing
- Use forward slashes and no leading './' or '/'
Example fix
# before (mise.toml) [monorepo.projects."cargo:app"] root = "/home/me/monorepo/crates/app" # after [monorepo.projects."cargo:app"] root = "crates/app"
Defensive patterns
Strategy: validation
Validate before calling
let root = std::path::Path::new(&cfg.root.unwrap_or_default());
if root.is_absolute() || root.components().any(|c| matches!(c, std::path::Component::Prefix(_) | std::path::Component::RootDir)) {
return Err(eyre::eyre!("project root must be workspace-relative: {}", root.display()));
} Type guard
fn root_is_relative(root: &Path) -> bool {
!root.is_absolute() && !root.components().any(|c| matches!(c, std::path::Component::Prefix(_) | std::path::Component::RootDir))
} Prevention
- Store and emit project roots relative to the workspace root in all tooling
- When generating config from absolute paths, always apply strip_prefix(workspace_root) first
- Use forward slashes in TOML paths; they work on Windows too and avoid Prefix components
When it happens
Trigger: Setting root = "/absolute/path/to/project" or "C:\\repo\\crates\\a" in [monorepo.projects."<id>"]; generating the override from tooling that emits absolute paths (editor plugins, generators using std::fs::canonicalize output); symlinks resolved to absolute paths before insertion.
Common situations: Script-generated mise.toml entries; developers assuming root behaves like a filesystem path; porting config between machines where absolute paths silently differ; Windows users pasting backslash absolute paths.
Related errors
- workspace project {:?} depends on unknown project {:?}
- workspace project {id:?} has root {root:?} that escapes the
- workspace path {path:?} is absolute; paths must be workspace
- workspace path {path:?} escapes the workspace root
- Cargo workspace member pattern {member:?} must be relative
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/fbf1acb68a51aa9d.
Report an issue: GitHub.