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, `open_or_create_subdir` inspects each path component's file type. If the component exists but is neither a directory nor a symlink, it returns `AlreadyExists` with "path component exists but is not a directory: {name}", because the traversal expected to descend into (or create) a directory there.
Source
Thrown at src/uucore/src/lib/features/safe_traversal.rs:586
/// * `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 85295bbf78)
Solutions
- Remove/rename the non-directory component so the directory can be created
- Use a different target path
- Check the existing path type and reconcile it before traversal
Example fix
# before mkdir -p out/data # out/data is a regular file # after mv out/data out/data.bak && mkdir -p out/data
Defensive patterns
Strategy: validation
Validate before calling
for ancestor in target.ancestors().skip(1) {
if ancestor.exists() && !ancestor.is_dir() {
return Err(format!("{} exists and is not a directory", ancestor.display()));
}
} Type guard
fn component_is_dir(p: &Path) -> bool {
p.symlink_metadata().map(|m| m.is_dir()).unwrap_or(false)
} Try / catch
match create_dir_all_safe(&target) {
Err(e) if e.kind() == io::ErrorKind::AlreadyExists
&& e.to_string().contains("not a directory") => {
eprintln!("{} blocks directory creation", target.display());
}
other => other?,
} Prevention
- Check intermediate path components before mkdir -p style logic
- Clean stale state between runs
- Avoid mixing file and directory names at the same path
When it happens
Trigger: Calling `create_dir_all_safe` on a path where an intermediate component is a regular file, FIFO, socket, etc. (e.g. path `a/b/c` where `a/b` is a regular file).
Common situations: A file was created where a directory was expected, leftover state from a previous run, typo'd paths colliding with an existing file name.
Related errors
- Is a directory
- Too many levels of symbolic links
- safe-traversal-error-invalid-fd
- mv-error-dangling-symlink
- mv-error-dest-appeared
AI-assisted analysis of uutils/coreutils@85295bbf78 (2026-08-31).
Data as JSON: /api/errors/93c9fbb2e0e0e8fb.
Report an issue: GitHub.