jdx/mise · error
refusing to replace non-directory path {}; set replace = tru
Error message
refusing to replace non-directory path {}; set replace = true to allow replacement What it means
Raised in ManagedDirectoryRequest::operation when a directory entry (any state) is planned and inspection returns ResourceAction::Unknown because the path exists as a non-directory (regular file, socket, etc.), and the entry does not opt in with replace = true. The library refuses to silently clobber non-directory filesystem objects to create a directory.
Source
Thrown at src/system/managed_files.rs:672
replace: config.replace,
notify: config.notify,
origin,
inspection: None,
})
}
pub(crate) fn plan(&self) -> Result<ResourcePlan> {
plan_directory(self).map(|plan| plan.with_origin(self.origin.clone()))
}
fn operation(&self) -> Result<Option<PrivilegedAction>> {
match self.plan()?.action {
ResourceAction::Noop => return Ok(None),
ResourceAction::Unknown if self.state == ManagedState::Absent => bail!(
"refusing to remove non-directory path {} as a directory; declare it in [bootstrap.files]",
self.path.display()
),
ResourceAction::Unknown => bail!(
"refusing to replace non-directory path {}; set replace = true to allow replacement",
self.path.display()
),
_ => {}
}
Ok(Some(match self.state {
ManagedState::Present => PrivilegedAction::CreateDirectory {
path: self.path.clone(),
owner: self.owner.clone(),
group: self.group.clone(),
mode: self.mode,
replace: self.replace,
},
ManagedState::Absent => PrivilegedAction::RemoveDirectory {
path: self.path.clone(),
recursive: self.recursive,
},
}))View on GitHub (pinned to afd2eddd3a)
Solutions
- Set replace = true on the directory entry to allow the library to remove the non-directory and create the directory.
- Check what the path actually is (ls -la) and manage it correctly via [bootstrap.files] instead if it should remain a file.
- Remove the blocking file manually, then re-run bootstrap.
- Pick a different path if the collision is unintentional.
Example fix
# before [[bootstrap.directories]] path = "/etc/myapp/conf.d" state = "present" # after [[bootstrap.directories]] path = "/etc/myapp/conf.d" state = "present" replace = true
Defensive patterns
Strategy: validation
Validate before calling
for path in &managed_dir_paths {
if let Ok(meta) = std::fs::metadata(path) {
if !meta.is_dir() && !replace_enabled(path) {
eprintln!("{} is not a directory; set replace = true or fix the entry", path.display());
}
}
} Type guard
fn is_directory_or_missing(path: &std::path::Path) -> bool {
match std::fs::metadata(path) {
Ok(m) => m.is_dir(),
Err(_) => true,
}
} Prevention
- Use replace = true only after confirming removal of the blocking file is intended.
- Check for stale files at directory paths before converging new hosts.
- Coordinate with tools/packages that may convert directories into files.
When it happens
Trigger: Converging a [bootstrap.directories] entry (typically state = "present") whose path exists as a non-directory on disk and `replace` is false/unset — the (ResourceAction::Unknown, non-Absent) arm.
Common situations: A package upgrade replaced a directory with a file; a stale plain file blocks a path the config wants as a directory; managing /etc paths where another tool left a file behind.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- refusing to replace non-file path {}; set replace = true to
- refusing to remove directory {} as a file; declare it in [bo
- refusing to remove non-directory path {} as a directory; dec
- refusing unsafe change to bootstrap user '{}'; inspect `mise
- refusing unsafe change to bootstrap compose project '{}'; in
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/c66934c2503cb73c.
Report an issue: GitHub.