{"record":{"id":"dc5bb1db46e40537","repo":"jdx/mise","slug":"refusing-to-replace-non-directory-path","errorCode":null,"errorMessage":"refusing to replace non-directory path: {}","messagePattern":"refusing to replace non-directory path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1419,"sourceCode":"            bail!(\"refusing to remove directory as a file: {}\", path.display())\n        }\n        Ok(_) => fs::remove_file(path).map_err(Into::into),\n    }\n}\n\nfn create_directory(\n    path: &Path,\n    owner: Option<&str>,\n    group: Option<&str>,\n    mode: u32,\n    replace: bool,\n) -> Result<()> {\n    match fs::symlink_metadata(path) {\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => fs::create_dir(path)?,\n        Err(error) => return Err(error.into()),\n        Ok(metadata) if metadata.file_type().is_dir() => {}\n        Ok(_) if !replace => {\n            bail!(\"refusing to replace non-directory path: {}\", path.display())\n        }\n        Ok(_) => {\n            fs::remove_file(path)?;\n            fs::create_dir(path)?;\n        }\n    }\n    set_metadata(path, owner, group, mode)\n}\n\nfn remove_directory(path: &Path, recursive: bool) -> Result<()> {\n    match fs::symlink_metadata(path) {\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),\n        Err(err) => Err(err.into()),\n        Ok(metadata) if !metadata.file_type().is_dir() => {\n            bail!(\"refusing to remove non-directory path: {}\", path.display())\n        }\n        Ok(_) if recursive => fs::remove_dir_all(path).map_err(Into::into),\n        Ok(_) => fs::remove_dir(path).map_err(Into::into),","sourceCodeStart":1401,"sourceCodeEnd":1437,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/managed_files.rs#L1401-L1437","documentation":"create_directory() refuses to replace an existing non-directory path (regular file, symlink, ...) with a directory unless the entry sets replace = true. With replace = true mise does remove_file() then create_dir() and applies metadata.","triggerScenarios":"A [bootstrap.directories] entry whose path exists as a file or symlink while the entry lacks replace = true.","commonSituations":"Converting a location that previously held a file into a directory; a leftover symlink from another tool occupying the path.","solutions":["Set replace = true on the directory entry","Or delete the offending file/symlink manually first, then re-run bootstrap"],"exampleFix":"# before: /opt/app is currently a regular file\n[bootstrap.directories]\n\"/opt/app\" = { mode = \"0755\" }\n\n# after\n[bootstrap.directories]\n\"/opt/app\" = { mode = \"0755\", replace = true }","handlingStrategy":"validation","validationCode":"match std::fs::symlink_metadata(path) {\n    Ok(m) if !m.file_type().is_dir() && !replace => {\n        return Err(eyre::eyre!(\"path exists as non-directory; set replace = true\"));\n    }\n    _ => {}\n}","typeGuard":"fn can_create_directory_here(path: &std::path::Path, replace: bool) -> bool {\n    match std::fs::symlink_metadata(path) {\n        Err(_) => true,\n        Ok(m) => m.file_type().is_dir() || replace,\n    }\n}","tryCatchPattern":null,"preventionTips":["Check what currently occupies a path before converting it to a managed directory","Use replace = true deliberately, understanding it removes the existing non-directory"],"tags":["filesystem","replace","path-type","managed-files"],"backgroundTag":"refusing-to-replace-existing-path","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}