jdx/mise · error

managed file parent does not exist: {}

Error message

managed file parent does not exist: {}

What it means

write_file() requires the parent directory to exist - mise does not implicitly mkdir -p for managed files. If fs::metadata(parent) returns NotFound, the write is refused before any mutation happens, leaving the old state intact.

Source

Thrown at src/system/managed_files.rs:1361

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() => {}
        Ok(_) if !replace => {
            bail!("refusing to replace non-file path: {}", path.display())
        }
        Ok(metadata) if metadata.file_type().is_dir() => {
            fs::remove_dir(path).wrap_err_with(|| {

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Add a [bootstrap.directories] entry for the parent so the run creates it before the file
  2. Or pre-create the directory yourself: sudo mkdir -p /opt/app

Example fix

# before
[bootstrap.files]
"/opt/app/settings.conf" = { content = "..." }

# after
[bootstrap.directories]
"/opt/app" = { owner = "app", mode = "0755" }
[bootstrap.files]
"/opt/app/settings.conf" = { content = "...", mode = "0644" }
Defensive patterns

Strategy: validation

Validate before calling

let parent = path.parent().ok_or_else(|| eyre::eyre!("no parent"))?;
if !parent.exists() {
    return Err(eyre::eyre!("managed file parent does not exist: {}", parent.display()));
}

Type guard

fn parent_exists(path: &std::path::Path) -> bool {
    path.parent().map(|p| p.exists()).unwrap_or(false)
}

Prevention

When it happens

Trigger: Declaring [bootstrap.files] "/opt/app/settings.conf" when /opt/app (or an ancestor) does not exist and no matching [bootstrap.directories] entry creates it.

Common situations: Fresh machine where the application directory was never created; assuming managed files auto-create their parent directories.

Related errors


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