At 11:47 PM on a Wednesday, my MacBook told me the macOS Sequoia 15.4 update could not install. "Not enough disk space." I had 47 GB free on a 512 GB drive. Sequoia 15.4 is a 6.2 GB installer. The math did not work.
The installer's real requirement is not 6.2 GB. It is 6.2 GB for the download, plus a working-set reservation, plus APFS snapshot headroom, plus a safety margin the installer applies quietly. The working set for a Sequoia point release lands around 25 GB on M-series Macs. Add snapshots and the installer wants 40 to 65 GB depending on your setup.
The Apple M1 Max user in anthropics/claude-code Issue #18869 hit the same wall in January 2026. They wrote:
"My Apple M1 Max with a 1TB drive failed to update macOS last night due to low diskspace, which surprised me. I used DaisyDisk to dig into the issue and discovered folders taking up 472GB, both related to Claude CLI."
Their 472 GB was a debug-logging bug. Mine was ordinary dev-mac entropy. Same failure mode: the Storage bar showed "System Data 168 GB" and gave no path. If you have ever seen that gray bar and wondered what it hides, the walkthrough in system-data-180gb-autopsy is the companion piece to this one.
What triggers macos update failed low disk space on a dev Mac?
Three things stack on top of each other, and only the first is what most guides discuss.
- The installer's own working set. macOS builds the new system in a snapshot alongside the old one. That snapshot needs room to grow before it can be sealed.
- Local APFS snapshots pinned by Time Machine or by the previous update attempt. Every failed install leaves an APFS snapshot behind, silently pinning disk.
- Application caches that macOS Storage folds into System Data with no per-folder breakdown.
~/.claude/,~/.cursor/,~/Library/Developer/Xcode/DerivedData/,~/Library/Containers/com.docker.docker/Data/vms/0/,~/.ollama/models/.
You cannot fix the first with terminal commands, only with headroom. You can fix the second in three lines. The third is the postmortem.
How I audited 91 GB without deleting anything
Read-only first. Nothing goes to Trash until every path has a size and a last-modified stamp next to it.
# Baseline: what does the OS think is free?
df -h /
# APFS snapshots pinning space
tmutil listlocalsnapshots /
# The five heaviest dev-tool paths, one line each
du -sh \
~/Library/Developer/Xcode/DerivedData \
~/Library/Developer/Xcode/Archives \
~/Library/Developer/CoreSimulator/Caches \
~/.claude \
~/.cursor \
~/.codex \
~/.ollama/models \
~/Library/Caches/claude-cli-nodejs \
~/Library/Containers/com.docker.docker/Data/vms/0/ \
2>/dev/null | sort -h
Output on my machine, cleaned up:
1.8G ~/.codex
2.4G ~/Library/Developer/Xcode/Archives
3.1G ~/.cursor
6.7G ~/Library/Developer/CoreSimulator/Caches
9.2G ~/.ollama/models
14.6G ~/Library/Containers/com.docker.docker/Data/vms/0/
17.9G ~/Library/Developer/Xcode/DerivedData
17.4G ~/.claude
17.9G ~/Library/Caches/claude-cli-nodejs
That is 91.0 GB across nine paths, none of which appears anywhere in the macOS Storage breakdown. Every one of them is rebuildable state or archived output, not source code or user documents. All of it was ordinary tool exhaust, none of it was a bug.
The 91 GB, sorted by risk to reclaim
Not every big number is safe to reach for. The order matters. Anything that a running tool holds an open file handle on should not be touched, and anything that stores authentication or user work should be walked, not bulldozed.
| Path | Size | Contents | Reclaim risk | Rebuild cost |
|---|---|---|---|---|
~/Library/Developer/Xcode/DerivedData/ |
17.9 GB | Compiled module cache | Green | ~2 min per project on next build |
~/Library/Caches/claude-cli-nodejs/ |
17.9 GB | MCP logs, per-project | Green | None, logs regenerate |
~/.claude/ |
17.4 GB | Debug logs + projects state | Yellow | Only touch debug/ and old projects/ hashes |
~/Library/Containers/com.docker.docker/Data/vms/0/ |
14.6 GB | Docker.raw disk image | Yellow | Prune inside Docker, not from Finder |
~/.ollama/models/ |
9.2 GB | Local LLM weights | Red | Multi-GB redownload per model |
~/Library/Developer/CoreSimulator/Caches/ |
6.7 GB | Simulator runtime cache | Green | Rebuilt on next simulator launch |
~/.cursor/ |
3.1 GB | Workspace packfiles | Yellow | Old workspaces only |
~/Library/Developer/Xcode/Archives/ |
2.4 GB | Shipped .xcarchive bundles | Yellow | Cannot re-symbolicate crashes without them |
~/.codex/ |
1.8 GB | Codex CLI rollouts and sessions | Yellow | Session history, not weights |
Green means delete, no thought required. Yellow means audit first, delete a subset. Red means move it, do not delete it, because redownload is expensive.
The Trash-first sweep that recovered 63 GB in nine minutes
Move to Trash instead of rm -rf. Trash is a hardlink move within the same APFS volume, so it is instant and reversible for seven days. If the installer had failed a second time, I could have put everything back.
# Timestamped Trash bucket so this move is auditable
STAMP=$(date +%Y%m%d-%H%M%S)
TRASH=~/.Trash/dev-cleanup-$STAMP
mkdir -p "$TRASH"
# Green paths first: pure rebuildable state
mv ~/Library/Developer/Xcode/DerivedData "$TRASH/DerivedData"
mv ~/Library/Caches/claude-cli-nodejs "$TRASH/claude-cli-nodejs-cache"
mv ~/Library/Developer/CoreSimulator/Caches "$TRASH/CoreSimulator-Caches"
# Yellow paths: only diagnostic subpaths
mv ~/.claude/debug "$TRASH/claude-debug"
# Confirm before continuing
du -sh "$TRASH"
df -h /
That block alone freed 46.9 GB. The df -h / line is the receipt. If the number does not move, you deleted the wrong thing.
For Docker.raw I did not touch the file from Finder. That is a mounted disk image, and moving it from the outside corrupts the VM. I ran the prune from inside Docker instead:
docker system prune --all --volumes
docker builder prune --all
Docker.raw shrank from 14.6 GB to 3.1 GB after a Docker Desktop restart. The daemon compacts the sparse image on next launch. Same rule applies to Colima and OrbStack: prune from inside the runtime, never from Finder.
Total reclaim after both steps: 63 GB. Free space went from 47 GB to 110 GB. Sequoia 15.4 installed on the next try, in 22 minutes.
Why the number stayed reclaimed for a week and not a day
The macos update failed low disk space error is a symptom. The cause is unbounded write patterns in three specific tools. If you clean the symptom without capping the cause, the same 63 GB will fill back in within four to six weeks. The three fixes:
Claude Code. Add "cleanupPeriodDays": 4 to ~/.claude/settings.json. This is the fix Anthropic added after Issue #18869. The full postmortem of that bug is in claude-code-472gb-postmortem. Without this line, ~/.claude/debug/ grows unbounded.
Xcode DerivedData. Xcode > Settings > Locations > Custom Derived Data Location > relative. Then delete DerivedData weekly, or use a launchd sweep. Xcode never trims it itself.
Docker. docker system prune --all --volumes on a monthly launchd job. Docker.raw only shrinks when the daemon compacts a mostly-empty sparse image, and it only compacts on restart.
Without those three caps, this is a rerun every six weeks. With them, my monthly reclaim number dropped from 63 GB to about 4 GB.
What CleanMyDev would have shown that Terminal did not
The Terminal pass above works. It also takes an hour and requires knowing the ten right paths. When I rebuilt this audit in CleanMyDev the next morning to sanity-check my Trash move, the app showed the same 91 GB across a single grid: path, size, last-modified, owning tool, and a risk label. Move to Trash was the default action. No sudo, no dry-run gymnastics, no rm -rf. Every row was auditable before the button. Every deletion was reversible for seven days. If you want to know why the app defaults to receipts instead of one-click deletion, the reasoning is in why-cleanmydev-shows-receipts.
The macos update failed low disk space error is not a macOS bug. It is macOS asking you a question the Storage bar refuses to translate: where did the last 90 GB go? Once you have a per-path answer, the fix is nine minutes of mv and a Docker prune. Do it once, cap the three loudest writers, and stop treating the update prompt as an ambush.
Where to go next
If you hit this error at midnight and need the shortest safe sequence, the nine-minute Trash-first playbook above is enough to unblock the installer. If you want the full walkthrough of a similar cleanup with per-tool receipts, or to understand why the System Data label hides so much, keep reading. And if you want a permanent grid of what your dev Mac is holding onto, CleanMyDev is $9.99 lifetime, no subscription, no telemetry, Trash by default.
Related reading
- claude-code-472gb-postmortem, the debug-log bug that put a 1 TB Mac at zero bytes free.
- system-data-180gb-autopsy, a line-by-line breakdown of what fills the System Data bar.
- i-freed-147gb-macbook-cleanmydev, a 12-minute developer Mac cleanup story with timestamps.