jdx/mise · error

managed file parent is not a directory: {}

Error message

managed file parent is not a directory: {}

What it means

write_file() requires the managed file's parent directory to already exist and be a directory. fs::metadata(parent) succeeded but reported a non-directory (regular file, symlink to a file, etc.), so mise refuses to clobber something occupying the would-be parent path before writing the target.

Source

Thrown at src/system/managed_files.rs:1356

    _mode: u32,
) -> Result<()> {
    bail!("managed system files are only supported on Unix")
}

fn write_file(
    path: &Path,
    content: &[u8],
    owner: Option<&str>,
    group: Option<&str>,
    mode: u32,
    replace: bool,
) -> Result<()> {
    let parent = path
        .parent()
        .ok_or_else(|| eyre!("managed file has no parent: {}", path.display()))?;
    match fs::metadata(parent) {
        Ok(metadata) if metadata.is_dir() => {}
        Ok(_) => bail!(
            "managed file parent is not a directory: {}",
            parent.display()
        ),
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
            bail!("managed file parent does not exist: {}", parent.display())
        }
        Err(error) => return Err(error.into()),
    }
    // Prepare the complete replacement before mutating the destination. In
    // particular, a metadata permission error must leave the old path intact.
    let mut temporary = tempfile::NamedTempFile::new_in(parent)?;
    temporary.write_all(content)?;
    set_metadata(temporary.path(), owner, group, mode)?;
    temporary.as_file_mut().sync_all()?;
    match fs::symlink_metadata(path) {
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
        Err(error) => return Err(error.into()),
        Ok(metadata) if metadata.file_type().is_file() => {}

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Remove or rename the file occupying the parent path, then re-run bootstrap
  2. Manage the conflicting file as absent first ([bootstrap.files] entry with state = "absent"), then declare the directory and the file
  3. Fix a mistyped path that collides with an existing file

Example fix

# before: a regular file exists at /srv/app, blocking the parent check
[bootstrap.files]
"/srv/app/settings.conf" = { content = "..." }

# after: delete the conflicting file once (rm /srv/app), then manage parent + file
[bootstrap.directories]
"/srv/app" = { mode = "0755" }
[bootstrap.files]
"/srv/app/settings.conf" = { content = "...", mode = "0644" }
Defensive patterns

Strategy: validation

Validate before calling

let parent = path.parent().ok_or_else(|| eyre::eyre!("no parent"))?;
match std::fs::metadata(parent) {
    Ok(m) if m.is_dir() => Ok(()),
    Ok(_) => Err(eyre::eyre!("parent is not a directory: {}", parent.display())),
    Err(e) => Err(e.into()),
}

Type guard

fn parent_is_directory(path: &std::path::Path) -> bool {
    path.parent()
        .and_then(|p| std::fs::metadata(p).ok())
        .map(|m| m.is_dir())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: Managing /opt/app/settings.conf while /opt/app exists as a regular file; any case where the literal parent component of the managed path is an existing non-directory.

Common situations: A leftover file where a directory was expected (e.g. /etc/app was once a file); a path typo that collides with an existing file.

Related errors


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