Diagnostic Playbook — Finding Hidden Space on macOS
When diskutil says X GB used but du can only find Y GB, follow this sequence. The steps are ordered by likelihood of finding the problem — deleted-open files before snapshots, because they’re more common and harder to detect.
The three classes of invisible space
| Class | What it is | Tool to detect |
|---|---|---|
| Deleted-But-Open Files | Process holds a file descriptor to a deleted file; blocks not freed until process exits | sudo lsof +L1 |
| APFS - Snapshots | Snapshot pins old block versions; space invisible to directory traversal | diskutil apfs listSnapshots |
| Firmlink traversal failure | du cannot descend from the Data volume root | Enumerate directories individually |
DaisyDisk, Finder, du, and find cannot detect any of these. They only see live files with directory entries.
Step 1: establish ground truth
diskutil apfs listNote the Capacity Consumed for each volume and Container Free Space. The Data volume (role: Data) is almost always where the missing space is.
For a single volume’s authoritative used space:
diskutil info disk3s5 | grep "Volume Used"Replace disk3s5 with your Data volume identifier from the listing.
Step 2: check deleted-open files FIRST
This is the single most common cause of large invisible disk usage and the one most tools (including DaisyDisk) cannot detect.
# Quick total (upper bound — double-counts shared file descriptors)
sudo lsof +L1 2>/dev/null | awk 'NR>1{sum+=$7} END{printf "%.1f GB in deleted-open files\n", sum/1073741824}'
# Show the biggest offenders
sudo lsof +L1 2>/dev/null | awk 'NR>1 && $7+0 > 100000000 {printf "%10.1f GB PID=%-8s %s %s\n", $7/1073741824, $2, $1, $9}' | sort -rn | head -30lsof double-counts shared descriptors
If multiple processes share the same open file descriptor,
lsofreports the file size once per process. Actual consumption can be much less than the sum. See Deleted-But-Open Files for details.
If this is large, kill or restart the offending process:
sudo kill <PID>
# Or for launchd-managed services:
sudo launchctl kickstart -k system/<service.label>Blocks are freed instantly.
Step 3: check snapshots
# Get device identifiers from Step 1, then:
diskutil apfs listSnapshots disk3s5 # Data volume
diskutil apfs listSnapshots disk3s1 # System volume
# Also check via Time Machine (can show snapshots diskutil misses)
tmutil listlocalsnapshots /
tmutil listlocalsnapshotdates /Look for:
- Non-Apple, non-TM snapshots (
com.bombich.ccc.*,com.arq.*) — these are orphaned com.apple.os.update-*on System volume — this is the SSV, expected, ~15 GBMSUPrepareUpdatesnapshots — staged but possibly incomplete macOS updates
Step 4: enumerate visible files (bypassing firmlinks)
du cannot traverse /System/Volumes/Data/ from its root due to firmlinks. Enumerate each top-level directory individually:
sudo du -sh /System/Volumes/Data/Applications/ \
/System/Volumes/Data/Library/ \
/System/Volumes/Data/Users/ \
/System/Volumes/Data/private/ \
/System/Volumes/Data/opt/ \
/System/Volumes/Data/usr/ \
/System/Volumes/Data/System/ \
/System/Volumes/Data/.DocumentRevisions-V100/ \
/System/Volumes/Data/.Spotlight-V100/ \
/System/Volumes/Data/.fseventsd/ \
/System/Volumes/Data/MobileSoftwareUpdate/ \
/System/Volumes/Data/cores/ 2>/dev/nullThen drill into the largest:
sudo du -hd1 /System/Volumes/Data/Users/yourusername/ 2>/dev/null | sort -rh | head -20
sudo du -hd1 /System/Volumes/Data/Library/ 2>/dev/null | sort -rh | head -20Step 5: check specific large consumers
# Docker (sparse file — use both ls and du)
ls -lh ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw 2>/dev/null
du -sh ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw 2>/dev/null
# Nix store (separate APFS volume — invisible to Data volume scans)
diskutil apfs list | grep -i nix
du -sh /nix/store/ 2>/dev/null
# VM volume (swap + sleep image)
ls -lh /private/var/vm/
# Corporate tools
sudo du -sh /Library/Application\ Support/*/ 2>/dev/null | sort -rh | head -20
# Xcode
sudo du -sh ~/Library/Developer/ 2>/dev/nullStep 6: reconcile
Add up all sources from Steps 2–5. The total should match diskutil info Volume Used Space within a few GB (the remainder is filesystem metadata and FileVault overhead).
If the numbers still don’t add up, you have one of:
- Deleted-open files you missed (re-run
lsof +L1— processes may have spawned since Step 2) - APFS clone extent sharing making
duovercount (see APFS - Copy-on-Write and Clones) - FileVault encryption overhead (typically small, but can be several GB)
Commands that do NOT work (and why)
| Command | Why it fails on macOS |
|---|---|
du -hd1 /System/Volumes/Data/ | Firmlinks block traversal at root |
du -hxd2 /System/Volumes/Data/ | Same — -x doesn’t help with firmlinks |
df -h / | Shows container-level info, not per-volume breakdown |
diskutil info / → “Purgeable Space” | Field doesn’t exist on all macOS versions/volume types |
| DaisyDisk / Finder “About This Mac” | Cannot see deleted-open files (no directory entries) |
See also
- Deleted-But-Open Files — the most common cause of large invisible usage
- APFS - What It Is — start here if the APFS concepts feel unfamiliar
- macOS Disk Reporting — why
dfanddugive wrong numbers - diskutil - The Ground Truth Tool — the key diagnostic tool