Skip to content
Latchkey

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.

.github/workflows/ci.yml
# unstable: hashes a file regenerated every build
key: deps-${{ hashFiles('**/build-info.json') }}
# build-info.json contains a timestamp, so the hash is always new

Common 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.

.github/workflows/ci.yml
- 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

  1. Print the computed key and confirm it is identical across runs with no dependency change.
  2. Exclude generated artifacts from the hashFiles glob.
  3. 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.

Frequently asked questions

What causes "Cache key unstable"?
Including a file that is rewritten each run (with a timestamp, build id, or random content) in hashFiles makes the key unique every time.
How do I fix Cache key unstable?
Hash the committed lockfile or manifest, which only changes when dependencies change.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card