Quick fix
# One-liner: locate the vhdx + check host drive free space (PowerShell)
Get-ChildItem "$env:LOCALAPPDATAPackages*LocalStateext4.vhdx" | Select FullName, @{n='GB';e={[math]::Round($_.Length/1GB,1)}}
Get-PSDrive C | Select Used, Free
WSL resumes writing immediately once the host drive has free space.
What you will run into
In WSL, extracting/compiling/writing large files fails with No space left on device, yet df -h / clearly shows hundreds of GB free (/dev/sdd 1007G 190G 766G 20% /).
Your first reaction: "I clearly have space" — this is WSL2's most classic paradox: df shows the virtual capacity, not the real size of the vhdx file on the host disk.
Why this happens
WSL2's ext4 filesystem lives on a dynamically expanding vhdx virtual disk:
dfshows the virtual capacity (up to ~1TB by default);- When a write needs the vhdx to physically expand, it requires free space on the host disk (C: by default);
- Host disk full → expansion fails → the kernel returns ENOSPC ("No space left on device").
Hence the paradox of "df shows space, but can't write". Classic issues: microsoft/WSL#1665 (random ENOSPC), #4699 (372 comments: deleting files doesn't give space back to the host).
WSL2's ext4 filesystem lives inside a vhdx virtual disk: df reports the virtual disk's capacity ceiling (1TB-class by default), while real usage comes from the physical expansion of the vhdx file.
When a write needs expansion, the kernel asks the host disk (C: by default) for space — if the host disk is full, expansion fails and the kernel reports that write as ENOSPC.
That is the two-ledger paradox: "virtual capacity shows free space, the physical host has none".
Deterministic takeaway: if df -h / has space but writes fail, check the host disk (df -h /mnt/c) and the vhdx size (ls -lh *.vhdx);
deleted files not shrinking the vhdx is normal (sparse files only grow), compact it manually with wsl --shutdown then Optimize-VHD/diskpart compact;
the long-term fix is migrating the distro to a disk with room (wsl --export/--import) rather than squeezing a nearly-full disk.
Step by step
1. Find which drive the vhdx is on — Required
PowerShell:
Get-ChildItem "$env:LOCALAPPDATAPackages*LocalStateext4.vhdx" | Select FullName
Or the registry HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\{GUID} BasePath.
2. Check the host drive's free space — Required
Get-PSDrive D
If the host drive Free is tiny (measured here: with D at 9GB free, a 2.7G write inside WSL hit ENOSPC) → free host-drive space (recycle bin / large files / other distros' vhdx) and it recovers immediately.
3. Make the vhdx give space back (root fix; deleting files doesn't shrink the disk) — Required
- New WSL (2.4.4+):
wsl --shutdownthenwsl --manage <distro> --set-sparse true; deleted files return space automatically; - Older versions:
wsl --shutdown+ admin diskpartcompact vdisk(or Hyper-VOptimize-VHD).
4. Move to a bigger drive — Required
wsl --export <distro> <file.tar>
At the new location wsl --import <distro> <dir> <file.tar> (after import, reset root/default distro settings; wsl --set-default).
5. Prevention — Required
docker-desktop and other distros each occupy their own vhdx; put large files on /mnt/c (direct host-drive passthrough, doesn't consume the vhdx).
How to confirm it works
dd if=/dev/zero of=/tmp/x.bin bs=1M count=5120 conv=fsync && rm /tmp/x.bin
No more No space left on device means success. Measured: before host cleanup, writing 5GB failed at ~2.7GB while df still showed 766G free; recovered after cleanup.
Other environments
| Environment | Notes |
|---|---|
| Default install (C drive) | vhdx in %LOCALAPPDATA%\Packages\*\LocalState\; free C space |
| Moved to D drive | Free D space; measured trigger at 9GB free on this machine |
| Space not returned after deleting files | vhdx doesn't auto-shrink; use --set-sparse / diskpart compact |
| docker-desktop | Its own vhdx takes space; handle the same way |
Symptom
Extracting/compiling/writing large files inside WSL fails with No space left on device, while:
$ df -h /
/dev/sdd 1007G 190G 766G 20% / # plenty free, right?
$ dd if=/dev/zero of=/tmp/x.bin bs=1M count=5120 conv=fsync
dd: IO error: No space left on device # fails after ~2.7G
Key traits: df shows plenty of free space (even 80% idle); the failure point looks random (different files during extraction); users instinctively say "I do have enough space on my device" (verbatim in microsoft/WSL#1665).
Cause
WSL2's ext4 filesystem lives on a dynamically-expanding vhdx virtual disk: df reports the *virtual* capacity (up to ~1TB by default), not the actual size of the vhdx file on the host drive. When a write inside WSL requires the vhdx to physically grow, but the host drive (C: by default, or wherever the distro was imported) lacks free space, the expansion fails and the kernel returns ENOSPC. Hence the paradox: "df shows space, writes still fail". Related classics: microsoft/WSL#1665 (random ENOSPC), #4699 (372 comments: deleting files never returns space to the host).
Solution
- Locate the vhdx drive first: registry
HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\{GUID}BasePath,
or PowerShell Get-ChildItem "$env:LOCALAPPDATA\Packages\*\LocalState\ext4.vhdx";
- Check the host drive's free space:
Get-PSDrivefor the drive holding the vhdx — in this repro, D: had only 9GB free
and a 2.7GB write inside WSL already hit ENOSPC. Freeing host space (recycle bin, large files, other distro vhdx files) restores it immediately;
- Return space to the host (root fix; deleted files do not shrink the disk):
- Newer WSL (2.4.4+):
wsl --shutdownthenwsl --manage <distro> --set-sparse true— sparse vhdx, space returns automatically on delete; - Older versions:
wsl --shutdown+ admindiskpart compact vdisk(or Hyper-VOptimize-VHD);
- Move to a bigger drive:
wsl --export <distro> <file.tar>→wsl --import <distro> <dir> <file.tar>at the new location
(note: after import, re-set the default distro/user as needed);
- Prevention: docker-desktop and other distros each own a vhdx; keep large files in /mnt/c (host passthrough, no vhdx growth),
or cap the vhdx size where supported.
Verification Evidence
- Local repro (2026-08-29, WSL Ubuntu, vhdx at D:\WSL\Ubuntu, host D: had only 9GB free):
- Baseline: df shows 766G free / vhdx file 194.90GB / D: Free 9.0GB;
- Repro: dd writing 5GB failed at ~2.7GB with
IO error: No space left on device, thendf -h /still showed 766G free; - Mechanism check: D: Free 9GB (no physical room for the vhdx to grow) vs df virtual capacity — same symptom class as #1665;
- Cleanup: after deleting the partial file, df recovered but D: Free and vhdx size stayed unchanged (deletion does not return space — the #4699 pain point);
- Not tested (needs admin/restart, honestly marked): diskpart compact, --set-sparse, --export/--import migration.
Evidence details kept locally (2026-08-29)
Related canonicals
Read in order: precondition -> same root / same domain / related:
- Same root:
- docker pull fails / mirror accelerators (same root: pull/extract reports
no space left on device— under WSL the common truth is a full host drive; check free space on the drive holding the vhdx first) - Cannot connect to the Docker daemon (same root: Docker-side connection/env issue; rule out daemon state before disk)
- ollama pull stuck/timeout (same root: ENOSPC during model download/import; models are 4~70GB, check disk first)
- pip install timeout/slow (same root: ENOSPC during download/install)
- npm install slow/hang (same root: ENOSPC during cache writes)
- Go module fetch slow/timeout (same root: ENOSPC during download/build)
Applicable tools (1)
This problem is linked from the tool pages below — reachable from either side.
wslBundled solutions (combos)
This problem is part of the following verified bundles.
Source & evidence
← Coding Agents & Terminal domain | Problem Catalog Experience | Facing another issue? Go to the Helpdesk