Automatone
HomeAbout

Automatone

AI tools, dev workflows, and automation. No hype, just what works.

Pages

HomeBlogAboutPrivacyTerms

Connect

GitHubRSS Feed

© 2026 Automatone. All rights reserved.

Admin
  1. Home
  2. ›Troubleshooting
  3. ›Fix Docker "no space left on device"

Fix Docker "no space left on device"

Sanchez Kim
Sanchez Kim
AI Engineer · June 29, 2026 · 8 min read

Docker filled the disk and now builds and pulls fail with 'no space left on device'. Diagnose with docker system df before deleting, escalate from a safe prune up to image and build-cache cleanup, and handle the traps most guides miss: inode exhaustion and Docker Desktop's VM disk that never shrinks on its own.

#docker#devops#troubleshooting#disk-space#docker-prune#wsl2#linux
Fix Docker "no space left on device"

Your build just died with no space left on device, or a docker pull stopped halfway, or a container refuses to start. Docker has filled its data directory and now everything is blocked. The fast way out is two commands. The careful way out — the one that doesn't delete data you'll miss — takes about five minutes and starts with looking before you delete.

Here's the short version, in escalation order. Run the diagnostic first, then climb the ladder only as far as you need:

docker system df            # see what's actually using space
docker system prune         # safe: stopped containers, unused networks, dangling images, build cache
docker system prune -a      # also removes ALL unused images (re-pull later)
docker builder prune -a     # nuke build cache specifically (often the real hog)

Stop as soon as you have enough room. Don't open with docker system prune -af --volumes — that --volumes flag is how people lose database data. More on that below.

Why this happens

Everything Docker stores — images, container writable layers, named and anonymous volumes, and build cache — lives under one directory on Linux, /var/lib/docker. When the partition holding that directory fills up, any operation that needs to write fails with no space left on device. Build cache is usually the surprise: every RUN step in a Dockerfile can leave an intermediate layer behind, and on a CI box those pile up fast.

There's a second cause that looks identical but isn't a byte problem at all: running out of inodes. We'll get to that, because the usual fix won't help if that's what bit you.

Step 1 — Diagnose before deleting

docker system df gives you the breakdown and, crucially, a RECLAIMABLE column showing what a prune could actually free:

docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          42        7         18.6GB    14.2GB (76%)
Containers      11        3         1.1GB     980MB (87%)
Local Volumes   9         4         6.3GB     2.1GB (33%)
Build Cache     156       0         22.4GB    22.4GB (100%)

If one row dwarfs the rest, you know where to aim. Add -v for a per-object listing so you can see exactly which images or cache entries are the offenders:

docker system df -v

Then check the host filesystem itself:

df -h /var/lib/docker     # bytes used/free
df -i /var/lib/docker     # inodes used/free

If df -h says you have free space but Docker still complains, look at df -i. An IUse% near 100% means you're out of inodes, not bytes — skip ahead to the inode section.

Terminal output of docker system df showing a reclaimable column with build cache as the largest entry

Step 2 — Safe cleanup

docker system prune

With no flags, this removes all stopped containers, networks not used by any container, dangling images, and unused build cache. It prompts before doing anything, and it leaves your tagged images, running containers, and all volumes alone.

Worth flagging because a lot of older posts get it wrong: modern docker system prune does clear build cache by default. If you read somewhere that you need a separate command for that, the article predates the current behavior. (Docker CLI reference)

For most "disk full" situations, this one command is the whole fix. Re-run docker system df afterward to confirm.

Step 3 — Aggressive cleanup

Still tight? Escalate. The -a flag widens the net from dangling images to all unused images:

docker system prune -a       # all unused images + everything from the safe prune
docker image prune -a        # just images, if that's all you want gone
docker builder prune -a      # just build cache, drop ALL of it

"Unused" here means no container references the image. You'll re-pull or rebuild those on next use, so this trades disk now for a slower next build. On a build server, docker builder prune -a is frequently the single biggest win — that 22GB of cache in the example above goes in one shot.

Step 4 — Volumes (the danger zone)

⚠️ This is where data gets destroyed. Read before you run.

docker volume ls            # look first — what volumes exist?
docker volume prune         # removes anonymous volumes not used by any container

The --volumes flag on docker system prune only touches anonymous volumes — named volumes are preserved by design, exactly so you don't wipe a database by accident (reference). That's the safety net. Don't defeat it by manually deleting named volumes unless you are certain nothing needs the data. If a volume backs a Postgres or MySQL container, pruning it is gone-for-good.

This is the real reason not to reach for docker system prune -af --volumes reflexively: -f skips the confirmation prompt, and --volumes adds volume deletion. Together, in a hurry, that's how a quick cleanup becomes an incident.

Special case — out of inodes, not bytes

If df -i showed IUse% at or near 100%, free bytes won't save you. Every file and directory consumes one inode, and overlay2 (Docker's storage driver) creates an inode per file in every image layer. Image-heavy hosts — think Python images with a large site-packages, or anything with thousands of small files — burn through inodes long before they run out of space.

On ext4 the inode count is fixed when the filesystem is formatted and can't be grown later. So the practical fixes are:

  • Prune images and containers (docker system prune -a) — deleting files frees inodes, same command, different resource.
  • If pruning isn't enough, the filesystem itself needs reformatting with more inodes (mkfs.ext4 -N) or Docker's data moved to a roomier filesystem (next section).

The tell is always df -i versus df -h disagreeing. (background)

Diagram contrasting a disk full of bytes versus a disk full of inodes

Special case — Docker Desktop on Mac and Windows

If you're on Docker Desktop, the Linux advice above silently half-works, and here's why: Docker's data doesn't sit on your host filesystem directly. It lives inside a single VM disk image. Pruning frees space inside that disk — but the disk file on your host does not shrink automatically.

On Windows with the WSL2 backend, that file is a VHDX (ext4.vhdx, typically under C:\Users\<you>\AppData\Local\Docker\wsl\data). WSL2 allocates up to a 1 TB virtual disk by default and grows the file on demand as Docker writes to it — but deleting images never grows it back down. To reclaim host space after pruning:

# Quit Docker Desktop first, then in an admin PowerShell:
wsl --shutdown
Optimize-VHD -Path "C:\Users\&#x3C;you>\AppData\Local\Docker\wsl\data\ext4.vhdx" -Mode Full
# or, on recent WSL builds:
wsl --manage &#x3C;distro> --resize &#x3C;size>

Docker Desktop also exposes a GUI path: Settings → Resources to cap the disk image size, and a Clean / Purge data button. (Hanselman's walkthrough, Microsoft Learn)

Permanent fix — move Docker's data root

If the disk keeps filling no matter how often you prune, the disk is just too small. Relocate /var/lib/docker to a bigger partition by setting data-root in /etc/docker/daemon.json:

sudo systemctl stop docker
sudo rsync -avxP /var/lib/docker/ /new/path/docker/
# edit /etc/docker/daemon.json:
#   { "data-root": "/new/path/docker" }
sudo systemctl start docker
docker run hello-world          # verify it works against the new location
# only after confirming: sudo rm -rf /var/lib/docker.old

The -x on rsync keeps it from crossing into other mounted filesystems, and -P lets you resume if it's interrupted. Verify with hello-world before you delete the old directory — not after. (guide)

Keep it from happening again

  • Schedule a periodic docker system prune -f on build servers (cron or a CI cleanup step). The -f is fine here precisely because it's unattended and you've decided what it removes.
  • Run throwaway containers with --rm so they clean up on exit instead of accumulating stopped containers.
  • Shrink images at the source: multi-stage builds and smaller base images (alpine, -slim, distroless) mean less to store and fewer inodes per image.
  • Watch docker system df as a habit, not just when something breaks.

Command reference

Command Removes Data risk
docker system df nothing (diagnostic) none
docker system prune stopped containers, unused networks, dangling images, build cache low
docker system prune -a + all unused images low (re-pull needed)
docker image prune -a all unused images low (re-pull needed)
docker builder prune -a all build cache low (rebuild needed)
docker volume prune anonymous unused volumes medium
docker system prune -af --volumes everything above, no prompt high — can delete data
df -i /var/lib/docker nothing (inode check) none

Start at the top, stop when you have room, and only reach the bottom row when you know exactly what's in your volumes.

References

  • Docker Docs — system prune
  • Docker Docs — volume prune
  • Docker Docs — Prune unused objects
  • DataCamp — No space left on device
  • Hanselman — Shrink WSL2 virtual disks
  • Microsoft Learn — Manage WSL disk space
  • Guguweb — Move Docker data directory

Related Posts

Fix "Permission denied (publickey)" for Git over SSH
Jun 26, 2026·6 min read

Fix "Permission denied (publickey)" for Git over SSH

A fast, ordered fix for the git@github.com: Permission denied (publickey) error over SSH. Start by reading the verbose ssh -vT output, then walk through key generation, loading the agent, adding the public key, remote URLs, permissions, and the port 443 fallback.

Troubleshooting
Fix "ModuleNotFoundError: No module named" in Python
Jun 24, 2026·6 min read

Fix "ModuleNotFoundError: No module named" in Python

Most ModuleNotFoundError cases aren't a missing package — they're an interpreter or environment mismatch. This guide gives you two diagnostic commands to pin down which of the six real causes you have, then the exact fix for each, plus a copy-paste cheat sheet.

Troubleshooting
Fix "CUDA out of memory" Errors in PyTorch
Jun 17, 2026·8 min read

Fix "CUDA out of memory" Errors in PyTorch

CUDA out of memory in PyTorch often fires while nvidia-smi still shows free VRAM, because the caching allocator needs a contiguous block, not just free space. This guide gives a copy-paste triage path from fastest fixes to fragmentation tuning, plus how to tell a real leak apart from fragmentation.

Troubleshooting

On this page

  • Why this happens
  • Step 1 — Diagnose before deleting
  • Step 2 — Safe cleanup
  • Step 3 — Aggressive cleanup
  • Step 4 — Volumes (the danger zone)
  • Special case — out of inodes, not bytes
  • Special case — Docker Desktop on Mac and Windows
  • Permanent fix — move Docker's data root
  • Keep it from happening again
  • Command reference
  • References