jdx/mise · error · eyre::Report

managed system path must be absolute

Error message

managed system path must be absolute: {}

What it means

Managed system files/directories must be declared with absolute paths, because they are applied by a privileged helper process whose working directory cannot be assumed. After `replace_path` substitution, `validate_privileged_target` rejects any relative path before absolutizing it.

Solutions

  1. Change the path to an absolute one, e.g. path = "/etc/myapp/app.conf".
  2. If the value was templated, fix the template/variable so it yields an absolute path.
  3. Use mise's path templating to anchor the path (e.g. off a known absolute base) instead of a bare relative segment.

Example fix

# before
[bootstrap.files.appconf]
path = "etc/myapp/app.conf"

# after
[bootstrap.files.appconf]
path = "/etc/myapp/app.conf"
Defensive patterns

Strategy: validation

Validate before calling

def assert_absent_free(p):
    from pathlib import Path
    p = Path(p)
    if not p.is_absolute():
        raise ValueError(f"managed system path must be absolute: {p}")
    return p

Prevention

When it happens

Trigger: A [bootstrap.files] `path` (or directory path) that is relative, e.g. "etc/myapp.conf" or "./conf", passed through `validate_privileged_target` during planning.

Common situations: Hand-writing config with paths copied relative to the project root; templating that produced an empty or relative value; moving an entry from a project-local file list into bootstrap.files without absolutizing it.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/system/managed_files.rs:1371

            Self::File
        } else if metadata.file_type().is_dir() {
            Self::Directory
        } else if metadata.file_type().is_symlink() {
            Self::Symlink
        } else {
            Self::Other
        }
    }
}

fn absolute_target(path: &str) -> Result<PathBuf> {
    let path = crate::file::replace_path(Path::new(path));
    validate_privileged_target(&path)
}

fn validate_privileged_target(path: &Path) -> Result<PathBuf> {
    if !path.is_absolute() {
        bail!("managed system path must be absolute: {}", path.display());
    }
    let path = path.absolutize()?.to_path_buf();
    if path == Path::new("/") {
        bail!("refusing to manage the filesystem root");
    }
    Ok(path)
}

fn parse_mode(mode: Option<&str>, default: u32) -> Result<u32> {
    let Some(mode) = mode else {
        return Ok(default);
    };
    let mode = mode.strip_prefix("0o").unwrap_or(mode);
    let parsed = u32::from_str_radix(mode, 8).wrap_err("mode must be an octal string")?;
    if parsed > 0o7777 {
        bail!("mode must be between 0000 and 7777");
    }
    Ok(parsed)

View on GitHub (pinned to 533346cc37)