WSL2 Ubuntu: Troubleshooting & Fixing ‘No Space Left on Device’ Due to Inode Exhaustion
Resolve 'No Space Left on Device' errors in WSL2 Ubuntu when df -h shows free space but df -i reports 100% inode usage. Learn to identify and clear inode hogs.
Resolve 'No Space Left on Device' errors in WSL2 Ubuntu when df -h shows free space but df -i reports 100% inode usage. Learn to identify and clear inode hogs.
Introduction
You're working within your Windows Subsystem for Linux 2 (WSL2) Ubuntu environment, and suddenly your applications start failing with "No space left on device" or similar errors. You instinctively run df -h to check disk usage, only to find that there appears to be ample free space. Confused, you might then run df -i, revealing the true culprit: 100% inode utilization. This guide will walk you through understanding why this happens in WSL2 and provide a comprehensive, step-by-step resolution.
Symptom & Error Signature
The primary symptom is applications failing to create new files or directories, or even write to existing ones, reporting disk space-related errors, despite df -h indicating available capacity.
Typical output when running df -h within your WSL2 instance:
user@hostname:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 251G 50G 201G 20% /
tmpfs 7.8G 0 7.8G 0% /mnt/wsl
none 7.8G 4.0K 7.8G 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 7.8G 0 7.8G 0% /run/shm
none 7.8G 0 7.8G 0% /run/user
Notice the Use% for /dev/sdb (your WSL2 root filesystem) is only 20%, showing plenty of free space (201G).
However, checking inode usage (df -i) reveals a different story:
user@hostname:~$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb 163840000 163840000 0 100% /
tmpfs 2048035 1 2048034 1% /mnt/wsl
none 2048035 2 2048033 1% /run
none 2048035 3 2048032 1% /run/lock
none 2048035 4 2048031 1% /run/shm
none 2048035 5 2048030 1% /run/user
Here, IUse% for /dev/sdb is 100%, indicating that all available inodes have been consumed.
Common application errors you might encounter:
No space left on device
Cannot create file: Disk quota exceeded
Error creating directory: Input/output error
Root Cause Analysis
Inodes (index nodes) are a fundamental data structure in Unix-like file systems (like ext4 used by WSL2) that describe a file system object such as a file or a directory. Each file and directory on a Linux system requires exactly one inode. An inode stores metadata about the file, such as its size, owner, permissions, timestamps, and a pointer to its data blocks on the disk. It does not store the file's name or its actual content.
The paradox of df -h showing free space while df -i shows 100% usage occurs when your system has created an extremely large number of very small files. While these small files may consume minimal actual disk space (bytes or kilobytes each), each one still consumes a full inode. Modern file systems allocate a fixed number of inodes when created, often proportional to the total size of the partition. If this fixed number is exhausted, no new files or directories can be created, even if gigabytes or terabytes of actual disk space remain free.
Common scenarios leading to inode exhaustion in WSL2:
- Development Caches: Package managers (npm, yarn, pip), build systems, and IDEs can generate millions of temporary or cached files.
- Session Files: Web applications (PHP, Python, Node.js) often store session data as tiny files in
/var/lib/php/sessionsor similar directories. - Temporary Files: Unmanaged
/tmpdirectories from various processes. - Log Files: Especially if logging is verbose and not properly rotated, or if a service is crashing rapidly, creating many small log segments.
- Docker Build Layers/Intermediate Files: Docker often creates many temporary files during complex build processes or in container volumes if not properly cleaned up.
- Version Control Systems: Large Git repositories with many small files or rapid changes can sometimes contribute, though less common as a primary cause.
- Unintentionally copied files: Recursive copies gone wrong, creating deeply nested directories with empty or tiny files.
WSL2 uses a virtual hard disk file (ext4.vhdx) stored on your Windows host. While this file can grow dynamically, the inode allocation within the ext4 filesystem inside WSL2 is determined during its initial creation and resizing. Even if the ext4.vhdx on Windows still has plenty of room to expand, the number of inodes within the ext4 filesystem might be fixed and fully utilized.
Step-by-Step Resolution
The resolution involves identifying directories with a high concentration of small files and safely cleaning them up.
1. Verify Inode Exhaustion
First, confirm that inode exhaustion is indeed the issue.
df -i
If /dev/sdb (or your root filesystem) shows 100% IUse%, proceed.
2. Locate Directories with High Inode Counts
The most effective way to find inode hogs is to count files per directory. Start from the root and drill down.
# Count files (including directories) in each top-level directory
echo "Inodes per top-level directory:"
sudo find / -xdev -printf '%hn' | sort | uniq -c | sort -rh | head -n 20
# Explanation:
# - `find / -xdev`: Search from root, do not cross filesystem boundaries.
# - `-printf '%hn'`: Print the directory name for each found file/directory.
# - `sort`: Sorts the list for `uniq -c`.
# - `uniq -c`: Counts consecutive identical lines (i.e., files per directory).
# - `sort -rh`: Sorts numerically in reverse (highest counts first).
# - `head -n 20`: Shows the top 20 directories.
This command will give you a good starting point, showing which directories contain the largest number of files/inodes. Pay close attention to /var, /usr, /opt, and user home directories (/home/<user>).
3. Clean Up Common Inode Hogs
Once you've identified potential problem areas, target these for cleanup.
a. Clear apt Package Cache
apt caches downloaded .deb files, which can accumulate over time.
sudo apt clean
b. Clear npm/yarn Caches
Node.js development often creates massive caches of tiny files.
# For npm
npm cache clean --force
# For yarn
yarn cache clean --all
c. Prune Docker Resources
Docker can leave behind a significant number of unused images, containers, volumes, and build cache. These often include many layers and temporary files.
# Prune all unused Docker containers, networks, images (dangling and unreferenced), and optionally volumes.
docker system prune -a
# If you also want to remove ALL volumes (use with extreme caution!)
# docker system prune -a --volumes
docker system prune -aremoves all stopped containers, all dangling images, all unused images (not just dangling ones), all unused networks, and optionally all build cache. Use with caution, as it will free up significant space and inodes but might remove resources you intended to keep.
d. Manage Log Files
Log files can proliferate, especially during debugging or if a service is misbehaving.
- Check log sizes:
sudo du -sh /var/log/* | sort -rh | head -n 10 - Clear specific log files (use with caution):
# Truncate a large log file without deleting it (useful for active logs) sudo truncate -s 0 /var/log/syslog # Example for other logs: # sudo truncate -s 0 /var/log/nginx/access.log # sudo truncate -s 0 /var/log/nginx/error.log - Run
logrotatemanually (forces rotation and compression):
This command forces the rotation of all configured logs, potentially creating new, smaller files and compressing old ones, freeing up inodes.sudo logrotate -f /etc/logrotate.conf
e. Clean Temporary Directories
Check /tmp, /var/tmp, and user-specific temporary directories.
# Remove old files from /tmp (older than 7 days)
sudo find /tmp -type f -atime +7 -delete
sudo find /tmp -type d -empty -delete # Delete empty directories
# Same for /var/tmp
sudo find /var/tmp -type f -atime +7 -delete
sudo find /var/tmp -type d -empty -delete
# Consider specific application temp directories (e.g., PHP sessions)
# For PHP sessions (example path, verify yours):
# sudo find /var/lib/php/sessions -type f -mmin +$(cat /etc/php/*/fpm/php.ini | grep "session.gc_maxlifetime =" | awk '{print $3}') -delete
Be extremely careful when using
rm -rforfind ... -deletein system directories. Always double-check your path and command before executing.find ... -deleteis generally safer as it only deletes files/directories that match the criteria.
4. Find and Delete Orphaned/Empty Files or Directories
Sometimes processes create many empty files or directories that persist.
# Find and delete empty files older than 30 days
sudo find / -xdev -type f -size 0 -atime +30 -delete
# Find and delete empty directories (use with caution, can remove useful empty scaffolding)
sudo find / -xdev -type d -empty -delete
The
find / -xdevcommand can take a very long time on large filesystems. Start with specific problematic directories identified in step 2.
5. Analyze Specific Application/User Directories
If the general cleanup doesn't resolve the issue, you'll need to dig deeper into the directories identified in step 2.
- Navigate to the suspicious directory (e.g.,
/var/www/html/mysite/cache). - Run the inode count command again within that directory:
cd /path/to/suspicious/directory sudo find . -xdev -printf '%hn' | sort | uniq -c | sort -rh | head -n 20 - Based on the output, investigate what application or process is creating these files and determine if they can be safely deleted or if the application needs its cache/temporary file management reconfigured.
6. Compact the WSL2 Virtual Disk (Optional, for general disk space cleanup)
While not directly related to inode exhaustion (as inodes are a filesystem metadata issue, not raw disk space), after a large cleanup, your ext4.vhdx file on Windows might still be large. You can reclaim this physical space on your Windows host.
Shut down all WSL2 instances: Open PowerShell or Command Prompt on Windows:
wsl --shutdownCompact the
ext4.vhdxdisk: Navigate to your WSL2 distribution's storage path. The default is usually:%LOCALAPPDATA%Packages<DistroName>LocalStatee.g.,C:Users<YourUser>AppDataLocalPackagesCanonicalGroupLimited.UbuntuonWindows_...LocalStateOpen Command Prompt or PowerShell as Administrator and run
diskpart:diskpartWithin
diskpart, execute:select vdisk file="C:Users<YourUser>AppDataLocalPackagesCanonicalGroupLimited.UbuntuonWindows_...LocalStateext4.vhdx" compact vdisk exitReplace the placeholder path with the actual path to your
ext4.vhdxfile. This process can take some time depending on the disk size and amount of free space.
7. Monitor Inode Usage
After cleanup, regularly monitor your inode usage, especially if you run services that generate many small files.
# Check current inode usage
df -i
# Set up monitoring (e.g., a simple cron job or systemd timer)
# Example cron entry to check inodes and email if over 90% (requires mail utilities)
# 0 * * * * df -i | grep /dev/sdb | awk '{print $5}' | sed 's/%//' | xargs -I {} bash -c 'if [ {} -ge 90 ]; then echo "WARNING: WSL2 Inodes at {}%"; fi' | mail -s "WSL2 Inode Warning" [email protected]
By systematically identifying and clearing inode-heavy directories, you can resolve the "No space left on device" errors in your WSL2 Ubuntu environment and maintain a healthy filesystem.