Linux Error Guide: 'rmdir: failed to remove: Directory not empty' — Fix It Safely
Fix 'rmdir: failed to remove: Directory not empty' on Linux: reveal hidden and open files, spot busy mountpoints and NFS silly-rename leftovers, safely.
- #linux
- #troubleshooting
- #errors
- #filesystem
Stuck on this Linux Admins error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
rmdir only removes empty directories, so it fails the moment anything remains inside — even things ls doesn’t show by default:
rmdir: failed to remove 'build': Directory not empty
You’ll see the same ENOTEMPTY condition from other tools and from rm when a mountpoint or busy file is involved:
rm: cannot remove 'cache': Directory not empty
mv: cannot move 'olddir' to 'newdir/olddir': Directory not empty
The frustrating case is when ls shows nothing but removal still fails. That almost always means hidden dotfiles, a filesystem mounted at that path, or deleted-but-still-open files the filesystem is holding onto (classically NFS “silly-rename” .nfs* files).
Symptoms
rmdirorrm -rreports “Directory not empty” on a directory that looks empty.ls dirshows nothing butls -A dirreveals hidden entries.- The directory is a mountpoint and refuses to empty until unmounted.
- Files reappear immediately after you delete them (a process is recreating them).
- On NFS, stubborn
.nfsXXXXfiles block the removal.
Common Root Causes
- Hidden dotfiles.
.git,.env,.DS_Store, or.cache— invisible to plainls, so the directory only looks empty. - It’s a mountpoint. A filesystem is mounted there; the mounted content can’t be deleted, only unmounted.
- NFS silly-rename files. Deleting a file that another process still has open makes NFS rename it to
.nfsXXXX; it stays until the handle closes. - A process is recreating files. A running service writes into the directory faster than you delete, so it’s never actually empty.
- Nested subdirectories.
rmdiris non-recursive; any subdirectory blocks it. - Immutable or special files. Files with the immutable attribute resist deletion, leaving the directory non-empty.
Diagnostic Workflow
First, see everything — including dotfiles — that’s actually in the directory:
ls -A dir # -A shows hidden entries (except . and ..)
find dir -mindepth 1 -maxdepth 1 -printf '%y %p\n' # type + name of each child
Check whether the path is a mountpoint rather than a normal directory:
mountpoint dir
findmnt -T dir
If files reappear or .nfs* files persist, find the process holding them open:
lsof +D dir 2>/dev/null | head
ls -A dir | grep -E '^\.nfs'
Look for immutable attributes that quietly block deletion:
lsattr dir 2>/dev/null
find dir -type f -exec lsattr {} \; 2>/dev/null | grep -- '-i-'
Example Root Cause Analysis
A cleanup script kept failing on a deploy host with rmdir: failed to remove 'releases/old': Directory not empty, yet ls releases/old printed nothing.
ls -A releases/old immediately revealed a .gitkeep and a hidden .env.local — the directory had never been empty, only visually empty. But after removing those, a second run still failed. This time lsof +D releases/old showed a long-running worker process with a log file open under that path; every time the script deleted the log, the worker had already reopened a new one, and on the NFS-mounted volume the delete had turned into a .nfs0000000123 silly-rename file that ls -A now exposed.
The correct fix was to stop the worker (or point it elsewhere) before cleanup, not to force-remove files it still held open. Once the process was stopped, the .nfs* handle closed, the directory truly emptied, and rm -r succeeded. The script was updated to check lsof +D and skip directories with open handles rather than fighting them.
Prevention Best Practices
- Use
ls -A(orfind) when auditing “empty” directories so hidden files never surprise you. - Stop or drain processes that write into a directory before deleting it; never fight a service that’s actively recreating files.
- Unmount mountpoints (and confirm with
mountpoint) before trying to remove them; deleting through a mount is wrong anyway. - On NFS, close file handles before deletion to avoid silly-rename
.nfs*leftovers, and expect them when apps hold deleted files open. - Prefer
rm -rfonly with a fully-qualified, double-checked path in scripts; log the target first so a variable that expands empty can’t wipe the wrong tree.
Quick Command Reference
# Reveal everything actually present
ls -A dir
find dir -mindepth 1
# Is it a mountpoint? Then unmount, don't delete
mountpoint dir
sudo umount dir
# Who is holding files open in there?
lsof +D dir
# Clear an immutable flag that blocks deletion
sudo chattr -i dir/stubbornfile
# Remove non-empty directory recursively (use a checked, absolute path)
rm -rf /full/path/to/dir
Conclusion
“Directory not empty” from rmdir simply means something is still inside — most often hidden dotfiles, a mounted filesystem, or deleted files a process still holds open (NFS .nfs* silly-renames). Use ls -A and find to see the real contents, mountpoint/findmnt to catch mounts, and lsof +D to catch open handles. Fix the underlying cause — stop the process, unmount the filesystem, clear an immutable flag — rather than blindly forcing removal, and always run rm -rf against a verified absolute path.
Fixed it? Get 500 Linux Admins & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.