uutils/coreutils · error · io::Error
path component exists but is not a directory
Error message
path component exists but is not a directory: {} What it means
In safe_traversal's create_dir_all_safe, open_or_create_subdir walks path components using directory file descriptors. When an existing component's file type is neither a directory nor a symlink, it returns AlreadyExists with 'path component exists but is not a directory: {name}' to mirror GNU coreutils' mkdir -p behavior.
Solutions
- Remove or rename the file occupying the component path
- Use a different target directory
- Check each component with metadata/symlink_metadata before creating
Example fix
// before
create_dir_all_safe("out/data") // out is a regular file
// after
if fs::symlink_metadata("out")?.is_file() { fs::remove_file("out")?; }
create_dir_all_safe("out/data"); Defensive patterns
Strategy: validation
Validate before calling
fn component_is_dir(p: &Path) -> bool {
std::fs::metadata(p).map(|m| m.is_dir()).unwrap_or(true) // missing => ok to create
} Type guard
fn is_dir_component(p: &Path) -> Option<bool> {
std::fs::symlink_metadata(p).ok().map(|m| m.is_dir())
} Try / catch
match create_dir_all_safe(path) {
Err(e) if e.to_string().contains("exists but is not a directory") => {
eprintln!("remove or rename the file occupying {path:?}");
}
r => r?,
} Prevention
- Don't create plain files at paths reserved for directories
- Clean build output trees between runs
- Check symlink_metadata on each path prefix before mkdir -p style operations
When it happens
Trigger: create_dir_all_safe("a/b/c") where `a` or `a/b` exists as a regular file, fifo, socket, etc., so opening it as a subdirectory is impossible.
Common situations: A file shadowing a directory that a previous run created; build scripts leaving a marker file where a directory is expected; package installs conflicting with existing files.
Related errors
- invalid link path
- invalid destination path
- mv-error-dest-appeared
- mv-error-inter-device-move-failed
- mv-error-inter-device-move-failed (from, to, err)
AI-assisted analysis of uutils/coreutils@92995feca2 (2026-09-20).
Data as JSON: /api/errors/93c9fbb2e0e0e8fb.
Report an issue: GitHub.
Appendix: source
Thrown at src/uucore/src/lib/features/safe_traversal.rs:602
/// * `parent_fd` - The parent directory file descriptor
/// * `name` - The name of the subdirectory to open or create
/// * `mode` - The mode to use when creating a new directory
///
/// # Returns
/// A DirFd for the subdirectory
fn open_or_create_subdir(parent_fd: &DirFd, name: &OsStr, mode: u32) -> io::Result<DirFd> {
match parent_fd.stat_at(name, SymlinkBehavior::NoFollow) {
Ok(stat) => {
let file_type = (stat.st_mode as libc::mode_t) & libc::S_IFMT;
match file_type {
libc::S_IFDIR => parent_fd.open_subdir(name, SymlinkBehavior::NoFollow),
libc::S_IFLNK => {
// Follow symlinks to directories (GNU coreutils behavior).
// O_DIRECTORY in open_subdir ensures we only succeed if the
// symlink resolves to a directory; dangling or non-dir symlinks error out.
parent_fd.open_subdir(name, SymlinkBehavior::Follow)
}
_ => Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!(
"path component exists but is not a directory: {}",
name.display()
),
)),
}
}
Err(e) if e.kind() == io::ErrorKind::NotFound => match parent_fd.mkdir_at(name, mode) {
Ok(()) => parent_fd.open_subdir(name, SymlinkBehavior::NoFollow),
// Another process created `name` between the stat and the mkdir
// (issue #12355). Open what it created; O_NOFOLLOW keeps a symlink
// that raced into the name from being followed.
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
parent_fd.open_subdir(name, SymlinkBehavior::NoFollow)
}
Err(e) => Err(e),
},View on GitHub (pinned to 92995feca2)