Debug-action-cache [ OFFICIAL ✪ ]
[debug] Resolved path: 'node_modules' -> '/home/runner/work/app/node_modules' [debug] Path exists: true [debug] Contents: [ 'react', 'lodash', '.bin' ] If you see Path exists: false , you know your working directory is wrong. Add working-directory: ./app to your step. You run a Windows runner and a Linux runner. They share the same cache key. Debug logs reveal:
| Symptom | Debug Log Evidence | Fix | | :--- | :--- | :--- | | Cache never restores | GET response: 404 for all keys | Check hashFiles glob pattern. Use ls before cache step to ensure file exists. | | Cache restores empty folder | Path '/cache/node_modules' does not exist | Your path is relative. Use absolute path or $ github.workspace /node_modules . | | Cache upload takes 20 minutes | Compressing 50,000 files | You are caching temporary files (e.g., __pycache__ ). Add !**/__pycache__ to exclude. | | Cache uses too much space | Cache size: 11.2GB (exceeds 10GB limit) | Split cache: One for node_modules , one for build . Use actions/cache/save conditionally. | | Random cache misses | restoreKeys: [ 'Linux-node-' ] matches Linux-node-stable | Make your restore-keys more specific, e.g., $ runner.os -node-$ github.ref - | The debug-action-cache flag is great for real-time runs. But what if the workflow succeeded three days ago and you want to see what was cached?
- name: Cache Node Modules uses: actions/cache@v4 env: CACHE_DEBUG: true with: path: node_modules key: $ runner.os -node-$ hashFiles('package-lock.json') V4 debug logs include timing metrics: debug-action-cache
[debug] Checking cache for key: Linux-node-abc123 [debug] restoreKeys: [ 'Linux-node-' ] [debug] Cache service URL: https://artifactcache.actions.githubusercontent.com/... [debug] Request headers: Authorization: 'Bearer ***', Accept: 'application/json' [debug] GET response: 404 (Not Found) [debug] Trying restore key: Linux-node- [debug] GET response: 200 OK [debug] Cache found: cacheKey: 'Linux-node-def456', archiveLocation: 'https://...' [debug] Downloading 234MB archive... [debug] Extracting to /home/runner/work/repo/node_modules Suddenly, you see why the wrong cache was restored (because the exact key failed, so it fell back to a prefix). Let's simulate a broken pipeline. You have a monorepo with Python and Node.js. Your Python cache keeps restoring a 3-month-old virtual environment. Step 1: Enable Debug Mode Set ACTIONS_STEP_DEBUG=true . Run the workflow. Step 2: Analyze the Cache Restoration Logic Look for the [debug] restoreKeys line:
- name: Generate cache key simulation id: sim run: | echo "hash=$(sha256sum package-lock.json | cut -d' ' -f1)" >> $GITHUB_OUTPUT - name: Attempt Cache Restore with Full Debug uses: actions/cache@v4 with: path: node_modules key: debug-$ runner.os -$ steps.sim.outputs.hash restore-keys: debug-$ runner.os - - name: Manual inspection run: | echo "=== CACHE DEBUG REPORT ===" echo "Node modules exist? $([ -d node_modules ] && echo 'YES' || echo 'NO')" echo "Count: $(find node_modules -type f 2>/dev/null | wc -l)" They share the same cache key
gh actions cache delete <KEY> --repo <owner>/<repo> Or use the community action actions/delete-cache with that exact key. Once you have basic visibility, you can move to advanced diagnostics. 1. Segmenting the Cache Archive The cache action creates a .tar archive. Debug logs reveal segmentation:
jobs: debug-cache: runs-on: ubuntu-latest env: ACTIONS_STEP_DEBUG: ${} ACTIONS_RUNNER_DEBUG: $ 'false' steps: - uses: actions/checkout@v4 | | Cache restores empty folder | Path
That is the difference between guessing and knowing. Happy debugging.