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

  1. Express the root relative to the workspace root: root = "crates/a"
  2. If tooling generates the entry, strip the workspace-root prefix (path.strip_prefix(workspace_root)) before writing
  3. 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

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


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/fbf1acb68a51aa9d. Report an issue: GitHub.