Skip to content
Latchkey

GitHub Actions Cache Not Saved After an Exact-Key Hit

actions/cache skips the save when an entry already exists for the exact key, because cache entries are immutable. If the content changed but the key did not, the new content is never stored.

What this error means

The post-job cache step logs that the cache already exists and is not saved, so updated dependencies are never persisted under that key and later runs restore stale content.

Actions log
Cache hit occurred on the primary key npm-abc, not saving cache.
# updated node_modules are not persisted because the key did not change

Common causes

Immutable cache keys

A cache key maps to one immutable entry. Once saved, the same key is never overwritten, so changed content under an unchanged key is lost.

Key not reflecting content changes

If the key does not include a hash of the inputs that actually changed, the new state cannot get its own entry.

How to fix it

Make the key reflect the content

Include a lockfile hash so a dependency change produces a new key and a fresh save, with restore-keys for fallback.

.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: node_modules
    key: npm-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      npm-

Use a rolling key when content changes often

  1. Add a build-cache style key that includes a date or counter when you genuinely want frequent refreshes.
  2. Rely on restore-keys to load the most recent prior entry.
  3. Avoid manual cache deletion as a workaround; fix the key instead.

How to prevent it

  • Tie the cache key to a hash of the content it stores.
  • Use restore-keys so a new key still restores a recent cache.
  • Do not expect the same key to update; design keys to roll forward.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →