Introduction

GitHub Actions caching is a powerful feature that speeds up workflows by storing and reusing files between runs. Common use cases include caching package dependencies, build outputs, and compiler artifacts. However, GitHub imposes limits on cache storage to ensure fair resource distribution across repositories. When caches exceed these limits, the save operation fails, and subsequent workflow runs lose the performance benefits of caching.

The primary limit is 10 GB per repository, with individual cache entries limited to 10 GB each. While these limits seem generous, they are quickly consumed when teams cache heavyweight directories like node_modules, entire build directories, or multiple large caches without proper cleanup. Understanding how to cache efficiently—storing only the files that matter while minimizing storage footprint—is essential for maintaining fast, reliable workflows.

The most common mistake is caching installed dependency directories (like node_modules for Node.js or .venv for Python) rather than package manager download caches. Installed directories contain compiled binaries, platform-specific files, and duplicate content that significantly increases cache size. Package manager caches store only the downloaded archives, which are smaller and more portable.

Symptoms

When GitHub Actions cache exceeds size limits, you will observe these symptoms:

  • Post-job cache save step warns "Cache size exceeded the maximum allowed size" in workflow logs
  • Builds become progressively slower because cache restore works inconsistently or fails entirely
  • Repository cache storage grows despite minimal dependency changes
  • Workflow logs show "Cache saved successfully" but actual restore returns empty
  • Cache entries are evicted earlier than expected due to repository-wide limit pressure
  • Multiple cache keys all fail to save due to combined size exceeding repository limit

Common error messages in workflow logs:

bash
Post job cleanup.
Error: Cache size exceeded the maximum allowed size of 10240 MB
Cache saved with key: npm-cache-abc123
Warning: Cache size is ~512 MB, please ensure the cache is below 10 GB
Error: Unable to save cache: cache entry size exceeds maximum limit

Workflow output showing cache failure:

bash
Run actions/cache@v4
Cache restore: npm-cache-
Error: Cache size exceeded the allowed limit. The cache was not saved.
Cache retained: 0 bytes
Post-job: Cache save failed

Common Causes

Several factors cause GitHub Actions cache size failures:

  1. 1.Caching full install directories: Caching node_modules, .venv, vendor, or similar directories stores compiled binaries, platform-specific files, and nested dependencies. These directories can be hundreds of megabytes or gigabytes, far exceeding optimal cache sizes.
  2. 2.Accumulating caches without cleanup: Over time, cache entries from old branches, outdated dependencies, and unused keys accumulate, consuming repository quota. Without automatic cleanup, caches grow unbounded.
  3. 3.Single cache key for too many files: Using one cache key for both dependencies and build outputs causes large archives. Changes to either invalidate the entire cache, forcing frequent large saves.
  4. 4.Platform-specific content in cache: Caches that include native binaries, compiled modules, or platform-specific executables may work on one runner but fail on others. They also consume extra space storing unnecessary platform variants.
  5. 5.Incorrect cache paths: Accidentally caching entire project directories (like .) or broad patterns that include source code, logs, and temporary files.
  6. 6.Too many parallel workflow caches: Multiple matrix jobs or parallel workflows each creating caches can rapidly fill the repository quota.
  7. 7.Development-only dependencies in cache: Caching development tools, test fixtures, or documentation that changes frequently without being needed in CI.

Step-by-Step Fix

Follow these steps to diagnose and resolve cache size issues:

Step 1: Check current cache usage and sizes

Before fixing, understand what's already cached:

```bash # List all caches in the repository via GitHub API gh api repos/:owner/:repo/actions/caches

# Or use the web interface # Navigate to: Actions > Caches in repository settings

# Get cache sizes programmatically gh api repos/:owner/:repo/actions/caches --jq '.actions_caches[] | {key: .key, size: .size_in_mb}' ```

Step 2: Delete oversized and stale caches

Clean up existing large caches:

```bash # Delete all caches for the repository gh api -X DELETE repos/:owner/:repo/actions/caches

# Delete specific cache by key gh api -X DELETE repos/:owner/:repo/actions/caches?key=npm-cache-

# Delete caches older than a specific timeframe # Note: GitHub automatically deletes caches after 7 days of no access # and unaccessed caches after 7 days

# Using GitHub web interface: # Actions > Manage workflows and caches > Delete cache entries ```

Step 3: Cache package manager download directories, not install directories

Use the appropriate setup action's built-in caching:

```yaml # Node.js - cache npm's global cache, not node_modules - uses: actions/setup-node@v4 with: node-version: 20 cache: npm # Uses ~/.npm directory

# Or for yarn - uses: actions/setup-node@v4 with: node-version: 20 cache: yarn # Uses .yarn/cache directory

# Python - cache pip's download cache, not .venv - uses: actions/setup-python@v5 with: python-version: '3.11' cache: pip # Uses ~/.cache/pip

# Or for poetry - uses: actions/setup-python@v5 with: python-version: '3.11' cache: poetry # Uses poetry's cache directory ```

Step 4: Configure custom cache paths efficiently

If you need custom caching, specify only necessary paths:

```yaml # WRONG: Caching full install directory (large) - uses: actions/cache@v4 with: path: node_modules key: node-modules-${{ hashFiles('package-lock.json') }}

# CORRECT: Caching npm cache (smaller) - uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ hashFiles('package-lock.json') }}

# For Gradle - cache only the dependency cache - uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: gradle-${{ hashFiles('/*.gradle*', '/gradle-wrapper.properties') }}

# For Maven - cache local repository - uses: actions/cache@v4 with: path: ~/.m2/repository key: maven-${{ hashFiles('pom.xml') }} ```

Step 5: Split caches by purpose

Keep different types of content in separate caches:

```yaml # Dependency cache - small, stable - uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ hashFiles('package-lock.json') }}

# Build cache - larger, but keyed separately - uses: actions/cache@v4 with: path: .next/cache key: nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ github.sha }} restore-keys: | nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}- nextjs-${{ runner.os }}-

# Cypress cache - separate from main build - uses: actions/cache@v4 with: path: ~/.cache/Cypress key: cypress-${{ hashFiles('package-lock.json') }} ```

Step 6: Measure directory sizes before caching

Add a step to check what you're caching:

```yaml - name: Check cache directory size run: | echo "Checking sizes of directories to cache..." du -sh ~/.npm 2>/dev/null || echo "~/.npm not found" du -sh node_modules 2>/dev/null || echo "node_modules not found" du -sh .next/cache 2>/dev/null || echo ".next/cache not found"

# Warn if too large SIZE=$(du -sm ~/.npm | cut -f1) if [ "$SIZE" -gt 500 ]; then echo "Warning: Cache directory is larger than 500MB" fi ```

Step 7: Implement cache cleanup strategy

Use restore-keys to gradually clean old caches:

yaml
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      npm-${{ runner.os }}-

This pattern allows partial restores and creates new caches when dependencies change, naturally cleaning old entries.

Step 8: Limit matrix workflow cache creation

For matrix builds, use shared keys or limit caching:

```yaml strategy: matrix: node-version: [18, 20, 22]

steps: # Only cache for one version to save space - if: matrix.node-version == '20' uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ hashFiles('package-lock.json') }} ```

Verification

After fixing cache configuration, verify it works:

```bash # Run workflow and check cache status gh run watch

# Verify cache was saved successfully gh api repos/:owner/:repo/actions/caches --jq '.actions_caches[] | select(.key | startswith("npm-")) | {key, size: .size_in_mb, created: .created_at}'

# Check workflow logs for cache messages gh run view --log | grep -i cache

# Expected output: # Cache restored successfully # Cache saved with key: npm-abc123 # Cache size: 45 MB ```

Prevention

To prevent cache size issues in the future:

  1. 1.Use built-in setup action caching: Prefer the cache parameter in setup-node, setup-python, setup-java, etc., which automatically caches the correct directories.
yaml
# Best practice: Use setup action caching
- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: 'npm'
  1. 1.Never cache full install directories: Avoid caching node_modules, .venv, vendor, or similar directories. These are large and contain platform-specific content.
  2. 2.Regularly audit cache usage: Periodically check cache sizes in the repository Actions settings and delete oversized entries.
bash
# Monthly cache audit script
gh api repos/:owner/:repo/actions/caches --jq '[.actions_caches[] | select(.size_in_mb > 100)] | length'
  1. 1.Use restore-keys for natural cleanup: Implement restore-key patterns that allow partial restores while creating fresh caches for new configurations.
  2. 2.Separate build and dependency caches: Keep dependency caches (small, stable) separate from build caches (larger, changes frequently).
  3. 3.Add size checks in workflow: Include steps that warn when cache directories exceed expected sizes, catching growth early.
  4. 4.Monitor repository cache quota: Track total cache storage over time and alert when approaching the 10 GB repository limit.
  • [WordPress troubleshooting: Fix IAM Access Denied 403 - Complete Tro](fix-iam-access-denied-403)
  • [GitHub Actions Artifact Expired or 403 Download Failed](github-actions-artifact-expired-403-download-failed)
  • [Fix Github Actions Artifact Upload Failed File Too Large 5gb Limit Issue in GitHub Actions](github-actions-artifact-upload-failed-file-too-large-5gb-limit)
  • [Fix Github Actions Aws S3 Deploy Credentials Expired Rotate Issue in GitHub Actions](github-actions-aws-s3-deploy-credentials-expired-rotate)
  • [Fix Github Actions Cache Evicted Manually Workflow Fails Download Issue in GitHub Actions](github-actions-cache-evicted-manually-workflow-fails-download)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "GitHub Actions Cache Save Failed Because the Cache Exceeded the Size Limit", "description": "Resolve GitHub Actions cache size limit failures by caching package manager directories instead of build outputs or node_modules, and by pruning stale caches.", "url": "https://www.fixwikihub.com/github-actions-cache-save-failed-exceeded-size-limit", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-01-23T07:17:43.267Z", "dateModified": "2026-01-23T07:17:43.267Z" } </script>