GitHub Actions Cache Never Hits - Key Changes Every Run
Your cache saves successfully but never restores because the key is different on every run. A stable cache key must derive only from inputs that change when the cached content should change.
What this error means
Every run shows a cache save and a subsequent cache miss, so caching adds overhead without ever speeding anything up. The key in the logs differs each run.
# unstable: hashes a file regenerated every build
key: deps-${{ hashFiles('**/build-info.json') }}
# build-info.json contains a timestamp, so the hash is always newCommon causes
Hashing a generated or volatile file
Including a file that is rewritten each run (with a timestamp, build id, or random content) in hashFiles makes the key unique every time.
Embedding run id or date in the key
Putting github.run_id, github.sha, or the current date in the key guarantees a fresh, never-matching key.
How to fix it
Derive the key only from stable inputs
Hash the committed lockfile or manifest, which only changes when dependencies change.
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
restore-keys: |
pip-${{ runner.os }}-Verify the key is stable
- Print the computed key and confirm it is identical across runs with no dependency change.
- Exclude generated artifacts from the hashFiles glob.
- Use restore-keys so even a changed lockfile restores a close prior cache.
How to prevent it
- Only hash committed, deterministic files for cache keys.
- Never include run id, SHA, or timestamps in a cache key.
- Log and review the cache key when tuning cache behavior.