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
- Remove or rename the file occupying the parent path, then re-run bootstrap
- Manage the conflicting file as absent first ([bootstrap.files] entry with state = "absent"), then declare the directory and the file
- 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
- Check parent paths before declaring nested managed files
- Prefer declaring the parent as a managed directory so the run is self-contained
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
- managed system path must be absolute: {}
- refusing to manage the filesystem root
- command does not exist: {}
- path "{path_raw}" must be absolute or start with ~/, ignorin
- mode must be between 0000 and 7777
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/843ba1d9e975218d.
Report an issue: GitHub.