jdx/mise · error · eyre::Report

refusing to replace non-directory path

Error message

refusing to replace non-directory path: {}

What it means

When creating a managed directory, the library stats the target path. If it exists as a non-directory (regular file, symlink to file, etc.) and `replace` was not requested, it refuses with this error rather than silently deleting a file to make room for a directory.

Solutions

  1. Set `replace: true` so the library removes the file before creating the directory
  2. Delete the conflicting file manually and re-run
  3. Fix the manifest path so it no longer collides with an existing file

Example fix

// before
create_managed_dir(Path::new("/etc/app/conf.d"), ReplaceMode::Keep)?; // a file exists there
// after
create_managed_dir(Path::new("/etc/app/conf.d"), ReplaceMode::Replace)?;
Defensive patterns

Strategy: validation

Validate before calling

fn check_dir_target(path: &std::path::Path, replace: bool) -> Result<(), String> {
    match std::fs::metadata(path) {
        Err(_) => Ok(()),
        Ok(m) if m.is_dir() => Ok(()),
        Ok(_) if replace => Ok(()),
        Ok(_) => Err(format!("{} exists as a file; pass replace", path.display())),
    }
}

Type guard

fn target_is_dir_or_absent(path: &std::path::Path) -> bool {
    std::fs::metadata(path).map_or(true, |m| m.is_dir())
}

Try / catch

match result {
    Err(e) if e.to_string().contains("refusing to replace non-directory") => {
        std::fs::remove_file(path)?; // after verifying the file is expendable
        retry_operation()?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling create managed directory with `replace: false` on a path occupied by a regular file — e.g. manifest defines directory "/etc/app/conf.d" but a stale file named "conf.d" exists.

Common situations: Path kind changed between tool versions or manifest edits; a file was accidentally created with the directory's name; leftover artifacts from a failed prior run.

Related errors


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

Appendix: source

Thrown at src/system/managed_files.rs:1603

    path: &Path,
    owner: Option<&str>,
    group: Option<&str>,
    mode: u32,
    replace: bool,
) -> Result<()> {
    match fs::symlink_metadata(path) {
        Err(error)
            if matches!(
                error.kind(),
                std::io::ErrorKind::NotFound | std::io::ErrorKind::NotADirectory
            ) => {}
        Err(error) => {
            return Err(error)
                .wrap_err_with(|| format!("failed to inspect directory {}", path.display()));
        }
        Ok(metadata) if metadata.file_type().is_dir() => {}
        Ok(_) if !replace => {
            bail!("refusing to replace non-directory path: {}", path.display())
        }
        Ok(_) => {
            fs::remove_file(path).wrap_err_with(|| {
                format!(
                    "failed to remove existing path before creating directory {}",
                    path.display()
                )
            })?;
        }
    }

    #[cfg(unix)]
    {
        let directory = open_or_create_directory_tree(path)
            .wrap_err_with(|| format!("failed to create directory {}", path.display()))?;
        set_directory_metadata(&directory, owner, group, mode)
            .wrap_err_with(|| format!("failed to set metadata on directory {}", path.display()))
    }

View on GitHub (pinned to 533346cc37)