jdx/mise · error
refusing to replace non-file path {}; set replace = true to
Error message
refusing to replace non-file path {}; set replace = true to allow replacement What it means
Raised in ManagedFileRequest::operation when a file entry (any state) is planned and inspection returns ResourceAction::Unknown because the path exists as something other than a regular file (directory, socket, etc.), and the entry does not opt in with replace = true. The library refuses to clobber non-file filesystem objects silently.
Source
Thrown at src/system/managed_files.rs:600
replace: config.replace,
notify: config.notify,
origin,
inspection: None,
})
}
pub(crate) fn plan(&self) -> Result<ResourcePlan> {
plan_file(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 directory {} as a file; declare it in [bootstrap.directories]",
self.path.display()
),
ResourceAction::Unknown => bail!(
"refusing to replace non-file path {}; set replace = true to allow replacement",
self.path.display()
),
_ => {}
}
Ok(Some(match self.state {
ManagedState::Present => PrivilegedAction::WriteFile {
path: self.path.clone(),
content: self.content.clone().expect("present file has content"),
owner: self.owner.clone(),
group: self.group.clone(),
mode: self.mode,
replace: self.replace,
},
ManagedState::Absent => PrivilegedAction::RemoveFile {
path: self.path.clone(),
},
}))View on GitHub (pinned to afd2eddd3a)
Solutions
- Set replace = true on the file entry to explicitly allow the library to remove and replace the non-file path.
- Verify the path is expected to be a non-file; if it should stay a directory, manage it via [bootstrap.directories] instead.
- Choose a different target path that does not collide with the daemon-created object.
- Stop whatever process recreates the object at that path before converging.
Example fix
# before [[bootstrap.files]] path = "/var/run/myapp/sock.conf" content = "..." state = "present" # after [[bootstrap.files]] path = "/var/run/myapp/sock.conf" content = "..." state = "present" replace = true
Defensive patterns
Strategy: validation
Validate before calling
for path in &managed_file_paths {
if let Ok(meta) = std::fs::symlink_metadata(path) {
if !meta.is_file() && !replace_enabled(path) {
eprintln!("{} is not a regular file; set replace = true or fix the entry", path.display());
}
}
} Type guard
fn is_regular_file(path: &std::path::Path) -> bool {
std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(true)
} Prevention
- Set replace = true deliberately on entries that may collide with daemon-created objects.
- Avoid managing runtime paths (sockets, /var/run) that services recreate as directories.
- Stat target paths before converging to detect non-file occupants early.
When it happens
Trigger: Converging a [bootstrap.files] entry (state = "present" or "absent"; for absent-and-directory see the sibling error) whose path exists as a non-regular-file and `replace` is false/unset — the (ResourceAction::Unknown, non-Absent) arm.
Common situations: A service created a directory or socket at the path the config wants to own; a symlink was replaced by a real directory; managing a path like /var/run/myapp that a daemon recreates as a directory on every start.
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-directory path {}; set replace = tru
- 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/6991963a7e0213ba.
Report an issue: GitHub.