jdx/mise · error

workspace project has absolute root ; roots must be…

Error message

workspace project {id:?} has absolute root {root:?}; roots must be workspace-relative

What it means

normalize_project_root validates each workspace project's root path. Roots must be relative to the workspace root; an absolute path would let a project live outside the workspace and breaks workspace-relative path resolution, so mise throws this error.

Solutions

  1. Replace the absolute root with a path relative to the workspace root, e.g. "services/api"
  2. Move the project directory under the workspace root if it currently lives outside it
  3. Re-run after normalizing separators (use forward slashes / relative components)

Example fix

# before
[workspace.project.api]
root = "/home/me/proj/services/api"
# after
[workspace.project.api]
root = "services/api"
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_relative_root(id: &str, root: &std::path::Path) -> Result<(), String> {
    if root.is_absolute() {
        return Err(format!("project {id}: root {root:?} must be workspace-relative"));
    }
    Ok(())
}

Type guard

let is_relative_root = |p: &std::path::Path| !p.is_absolute();

Try / catch

if let Err(e) = normalize_project_root(&id, &root) {
    if e.to_string().contains("absolute root") {
        let rel = root.strip_prefix(base).unwrap_or(&root);
        eprintln!("use workspace-relative root, e.g. {rel:?}");
    }
}

Prevention

When it happens

Trigger: A [workspace.project] root value like "/home/me/proj" or "C:\\proj" is passed to normalize_project_root for project {id}.

Common situations: Copy-pasting an absolute path from a file manager into a project's root field; generating configs from scripts that emit absolute paths.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: 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 533346cc37)