🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

GitHub Actions Runner Out of Disk Space: Fix in 5 Minutes

CI failing with 'No space left on device' on GitHub Actions or self-hosted runners? Here is exactly how to diagnose what's eating disk — Docker layers, build artifacts, or the runner's own accumulation — and fix it for good.

Shubham4 min read
Share:Tweet

"No space left on device" mid-build is one of the more frustrating CI failures because the error surfaces wherever the disk happened to fill up — a docker build step, a npm install, a test run — not at the actual point where space was consumed. Here is how to find and fix the real cause.

Step 1: See What's Actually Eating Space

yaml
# Add this as an early debug step whenever disk issues are suspected
- name: Check disk space
  run: |
    df -h
    du -sh /* 2>/dev/null | sort -rh | head -10
    docker system df    # If Docker is involved

On GitHub-hosted runners, this is the fastest way to confirm you're actually hitting the runner's disk limit (typically ~14GB free on standard runners) rather than something else.

Cause 1: Docker Images/Layers Accumulating Across Jobs

bash
docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          47        3         18.3GB    17.8GB (97%)
# Containers      12        1         245MB     240MB (98%)

Every docker build and docker pull in a workflow leaves layers behind. On GitHub-hosted runners this resets each run, but on self-hosted runners this accumulates across every job that ever ran on that machine.

Fix — prune after builds, and add scheduled cleanup on self-hosted runners:

yaml
- name: Build image
  run: docker build -t myapp .
 
- name: Clean up Docker
  if: always()
  run: docker system prune -af --volumes
bash
# On self-hosted runners, also add a scheduled cron cleanup independent of jobs
# (cron on the runner host itself)
0 3 * * * docker system prune -af --volumes --filter "until=24h"

Cause 2: GitHub-Hosted Runner's Pre-Installed Software Eating Your Budget

Standard GitHub-hosted runners ship with a large amount of pre-installed software (multiple language runtimes, Android SDK, etc.) that you likely don't need for any given job — it eats into your usable disk before your job even starts.

yaml
- name: Free up disk space
  run: |
    sudo rm -rf /usr/share/dotnet
    sudo rm -rf /usr/local/lib/android
    sudo rm -rf /opt/ghc
    sudo rm -rf /opt/hostedtoolcache/CodeQL
    df -h

This single step commonly frees 20-30GB on standard GitHub-hosted runners before your build even starts — worth adding as an early step in any workflow that's tight on space, rather than debugging it after the fact.

Cause 3: Build Artifacts and Cache Growing Unbounded

bash
du -sh ~/.npm ~/.cache ~/.m2 ~/.gradle 2>/dev/null
# Package manager caches can silently grow to several GB over time,
# especially on self-hosted runners that persist between jobs

Fix — bound your cache size explicitly, don't let it grow forever:

yaml
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}
    # actions/cache itself has per-repo limits (10GB), but local caches
    # on self-hosted runners need their own cleanup policy
bash
# On self-hosted runners — cap and periodically clear local package caches
npm cache clean --force
find ~/.m2/repository -type f -atime +30 -delete    # Remove Maven artifacts unused in 30 days

Cause 4: Test Artifacts, Coverage Reports, and Logs Never Cleaned Up

bash
find . -name "*.log" -o -name "coverage" -o -name "test-results" | xargs du -sh 2>/dev/null | sort -rh | head -10

On self-hosted runners, if actions/checkout isn't cleaning the workspace between runs (or jobs write outside the workspace), test artifacts from every historical run can accumulate.

Fix — ensure clean checkouts and explicit artifact cleanup:

yaml
- uses: actions/checkout@v4
  with:
    clean: true    # Default true, but confirm it's not disabled
 
- name: Clean workspace after job
  if: always()
  run: rm -rf coverage/ test-results/ *.log

Cause 5: Self-Hosted Runner Disk Genuinely Too Small for the Workload

bash
df -h /home/runner
# If you're consistently near capacity even after cleanup, the disk is
# undersized for what you're actually running (large monorepo, big Docker images)

Fix — resize the underlying volume, don't just keep fighting cleanup:

bash
# Example for a cloud VM-backed self-hosted runner
aws ec2 modify-volume --volume-id vol-0abc123 --size 100
sudo growpart /dev/xvda 1
sudo resize2fs /dev/xvda1

If you're spending significant workflow time on cleanup steps every run, that's usually a signal the runner is undersized, not that you need cleverer pruning.

Diagnostic Checklist

bash
df -h                                    # overall disk usage
docker system df                          # Docker-specific breakdown
du -sh /* 2>/dev/null | sort -rh | head   # top-level directory usage
du -sh ~/.npm ~/.cache ~/.m2 2>/dev/null  # package manager caches

More CI/CD troubleshooting? Read our GitHub Actions cache not working fix and Docker build slow no cache fix.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments