Git & CI/CD Advanced

Troubleshooting GitHub Actions Disk Space Errors on macOS Self-Hosted Runners

Resolve GitHub Actions 'out of disk space' errors when running workflows locally on macOS. Optimize runner resources for successful CI/CD builds.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Resolve GitHub Actions 'out of disk space' errors when running workflows locally on macOS. Optimize runner resources for successful CI/CD builds.

A common challenge when operating self-hosted GitHub Actions runners, particularly on macOS environments, is encountering "out of disk space" errors during build processes. This issue can abruptly halt CI/CD workflows, leading to failed deployments, prolonged development cycles, and increased frustration. This guide provides a comprehensive, highly technical approach to diagnose and resolve disk space exhaustion specifically on macOS local environments running GitHub Actions self-hosted runners.

Symptom & Error Signature

Users will typically observe a workflow failure in their GitHub Actions UI, with the build step reporting an error related to disk capacity. The exact error messages can vary depending on the specific build tool or operation failing, but they generally converge on "No space left on device" or similar indications of storage exhaustion.

Here are common manifestations in workflow logs:

##[error]No space left on device
fatal: Could not write file .git/logs/HEAD: No space left on device
Error: Failed to write cache entry. No space left on device
[webpack-cli] Failed to write file: /Users/runner/work/my-repo/my-repo/dist/bundle.js
Error: No space left on device

If using Docker within the workflow, you might see:

error during connect: Post "http://docker.example.com/v1.24/build?buildargs=%7B%7D&cachefrom=%5B%5D&...": No space left on device

Often, the underlying system log (or the runner's _diag folder logs) might show:

df -h /Users/runner/work
Filesystem     Size   Used  Avail Capacity iused      ifree %iused  Mounted on
/dev/disk1s1  460Gi  459Gi    1Gi   100% 1234567 1234567890    0%   /

Root Cause Analysis

The "out of disk space" error on a macOS self-hosted runner typically stems from one or more of the following underlying issues:

  1. Insufficient Initial Disk Provisioning: The macOS machine (physical or virtual) hosting the runner simply doesn't have enough base disk space for the OS, applications, and anticipated build artifacts.
  2. Accumulation of Build Artifacts and Caches:
    • Project Dependencies: node_modules, Pods, Maven repositories, Swift Package Manager caches, etc., can consume significant space, especially across multiple projects or branches.
    • Xcode Derived Data: Xcode's build output, indexing data, and intermediate files (~/Library/Developer/Xcode/DerivedData) grow rapidly.
    • Package Manager Caches: npm, yarn, homebrew, pip, bundler all maintain local caches for speed, which can bloat over time.
    • GitHub Actions Runner Caches: The actions/cache mechanism, while beneficial, can accumulate large amounts of data if not managed with appropriate key and restore-keys strategies or if cleanup is neglected.
  3. Docker Image Layer Bloat: If workflows utilize Docker, accumulated dangling images, unused containers, and build cache layers can quickly consume gigabytes.
  4. Temporary Files and Logs: OS-level temporary directories (/tmp, /var/tmp), system logs, and specifically the GitHub Actions runner's _diag folder can grow large. The _diag folder contains detailed runner and job logs, which can be verbose.
  5. Simulators and Old Xcode Versions: macOS development environments often house multiple Xcode versions and a plethora of iOS/watchOS/tvOS simulators, many of which may be unused.
  6. Lack of Automated Cleanup: Without proactive cleanup routines, disk space on a continuously used self-hosted runner will inevitably dwindle.

Step-by-Step Resolution

Addressing disk space issues requires a multi-faceted approach involving system cleanup, workflow optimization, and proactive monitoring.

1. Assess Current Disk Usage

Begin by understanding what is consuming disk space.

  1. Overall Disk Usage:

    df -h /
    

    This command shows the disk space usage for the root filesystem, which typically includes the GitHub Actions _work directory.

  2. Identify Largest Directories: Navigate to common problem areas and use du (disk usage) to find the largest directories.

    # Check the runner's work directory
    sudo du -sh /Users/runner/actions-runner/_work/*
    
    # Check Xcode related directories
    du -sh ~/Library/Developer/Xcode/DerivedData
    du -sh /Applications/Xcode.app # If multiple Xcodes, check others too
    
    # Check Docker directories (if Docker Desktop is used)
    du -sh ~/Library/Containers/com.docker.docker/Data/*
    
    # Check system caches and logs
    du -sh ~/Library/Caches
    du -sh /var/log
    

    For a more granular view within a directory, use:

    sudo du -h -d 1 /path/to/directory | sort -rh
    

2. Clean macOS System Components

Perform thorough cleanup of macOS-specific artifacts that commonly consume significant disk space.

  1. Xcode Derived Data & Simulators:

    Deleting Derived Data will force Xcode to re-index and re-build projects, which might take longer on the next compilation. This is safe for a CI runner environment.

    # Clear Xcode Derived Data
    rm -rf ~/Library/Developer/Xcode/DerivedData/*
    
    # Delete unavailable simulators and runtimes
    # This command removes simulators for OS versions no longer supported or installed.
    xcrun simctl delete unavailable
    
    # Optionally, list all simulators and manually delete specific ones
    # xcrun simctl list devices
    # xcrun simctl delete <Device UDID>
    
    # Clear CoreSimulator devices (if issues persist, be careful with this)
    rm -rf ~/Library/Developer/CoreSimulator/Devices/*
    
  2. Homebrew Cache and Old Versions: If Homebrew is used to manage tools, clean its cache.

    brew cleanup
    brew autoremove
    
  3. macOS User Caches and Logs:

    While generally safe, be cautious when deleting arbitrary files from ~/Library/Caches. It's best to target known large caches.

    # Remove user application caches
    rm -rf ~/Library/Caches/*
    
    # Clear application support caches (e.g., specific app caches)
    # Be more selective here, as some apps store critical data
    # Example: rm -rf ~/Library/Application Support/Slack/Cache
    

3. Optimize Docker Usage (If Applicable)

If your GitHub Actions workflows use Docker, container and image bloat is a prime suspect.

  1. Prune Docker System:

    The docker system prune -a --volumes command is aggressive. It will remove all stopped containers, all networks not used by at least one container, all dangling images, all build cache, and all unused volumes. Ensure no critical data is in volumes before running this.

    docker system prune -f
    docker system prune -a --volumes -f
    
    • docker system prune -f: Removes all stopped containers, all networks not used by at least one container, and all dangling images.
    • docker system prune -a --volumes -f: Adds removal of all unused images (not just dangling ones) and all unused volumes.
  2. Configure Docker Desktop Disk Image Size: For macOS, Docker Desktop uses a virtual disk image. You can configure its size in Docker Desktop preferences (Settings > Resources > Disk image size). Increase it if builds frequently exceed the current limit, or decrease it if too much space is allocated unnecessarily.

4. Manage Node.js/NPM/Yarn Caches (If Applicable)

JavaScript projects frequently accumulate large dependency caches.

  1. Clean NPM/Yarn Caches:

    npm cache clean --force
    yarn cache clean --all
    
  2. Remove node_modules: In workflows, consider removing node_modules after a successful build if they are not needed for subsequent steps or artifact storage.

    - name: Clean node_modules
      if: always() # Run even if previous steps fail
      run: rm -rf node_modules
      working-directory: ${{ github.workspace }}/path/to/project
    

5. Configure GitHub Actions Workflow for Disk Efficiency

Proactive measures within your workflows can prevent future disk space issues.

  1. Manage Runner's _diag Folder: The _diag folder contains detailed logs for each job. Over time, this can grow significantly. There isn't a direct built-in action to prune this, but you can schedule a cron job on the runner machine or add a cleanup step.

    # Example command to clean old diag files (e.g., older than 7 days)
    # BE CAREFUL with 'find' and 'rm'. Test before running in production.
    find /Users/runner/actions-runner/_diag -type f -mtime +7 -delete
    
  2. Use actions/cache Effectively: While actions/cache saves time, misconfigured keys or excessive caching can consume disk space.

    • Specificity: Use specific keys. E.g., key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    • Cleanup: Ensure old cache entries are eventually purged. GitHub automatically prunes old caches, but if keys change frequently, new large caches are created.
    - name: Cache Node.js modules
      uses: actions/cache@v4
      with:
        path: ~/.npm
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-
    
  3. Delete Large Artifacts After Upload: If your workflow creates large build artifacts that are uploaded (e.g., using actions/upload-artifact), delete them from the runner's disk immediately after upload.

    - name: Build large artifact
      run: npm run build-heavy
    
    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: my-heavy-artifact
        path: dist/
    
    - name: Clean up local artifact
      run: rm -rf dist/
    
  4. Clean Temporary Build Directories: Many build systems create temporary directories. Add explicit cleanup steps.

    - name: Run complex build process
      run: ./build.sh
    
    - name: Clean temporary files
      if: always()
      run: |
        echo "Cleaning up temp directories..."
        rm -rf /tmp/my-build-temp-*
        # Add project-specific cleanup here
    

6. Increase Disk Space

If all optimization efforts are insufficient, the ultimate solution is to provide more disk space.

  • Physical Disk Upgrade: For a physical macOS machine, upgrade to a larger SSD.

  • Virtual Machine Disk Expansion: If the runner is running in a macOS VM, expand the virtual disk size in your hypervisor (e.g., VMware Fusion, Parallels Desktop, Anka, UTM). This often requires resizing the partition within macOS afterwards (Disk Utility or diskutil command line).

    # After resizing the VM disk in your hypervisor, you might need to extend the partition:
    # List disks and partitions
    diskutil list
    
    # Identify the partition to extend (e.g., disk0s2)
    # Then use 'resizeContainer' if it's an APFS container, or 'resizeVolume' for HFS+
    # Example for APFS (adjust disk identifier as per 'diskutil list'):
    sudo diskutil apfs resizeContainer disk0s2 0
    # The '0' indicates to resize to the maximum available space.
    

7. Monitor & Automate Cleanup

Implement monitoring and automation to prevent recurrence.

  1. Disk Usage Monitoring: Use tools like Prometheus Node Exporter (with a macOS collector) or simple shell scripts combined with cron to regularly check disk usage (df -h) and send alerts (e.g., via email, Slack, PagerDuty) when thresholds are breached.

  2. Scheduled Cleanup Cron Jobs: Set up cron jobs on the macOS runner machine to perform routine cleanups.

    # Open crontab for editing
    crontab -e
    
    # Add entries (example: daily at 2 AM)
    # Clear Xcode Derived Data
    0 2 * * * rm -rf ~/Library/Developer/Xcode/DerivedData/* > /dev/null 2>&1
    
    # Delete unavailable simulators
    0 2 * * * xcrun simctl delete unavailable > /dev/null 2>&1
    
    # Prune Docker (adjust frequency based on usage)
    30 2 * * * docker system prune -f > /dev/null 2>&1
    45 2 * * * docker system prune -a --volumes -f > /dev/null 2>&1
    
    # Clean Homebrew cache
    0 3 * * * /usr/local/bin/brew cleanup > /dev/null 2>&1
    

    Ensure that the user running the cron job has the necessary permissions. For brew and docker commands, the user account for the cron job must be able to execute these. Consider using sudo if absolutely necessary, but generally try to run these as the user owning the files.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.