CircleCI Partial Cache Restore Brings Stale Deps - Fix Fallbacks
After a lockfile change, the exact cache key misses, a broad prefix fallback restores an old cache, and the install step does not reconcile it - so the job runs with stale dependencies that pass cache lookup but no longer match the lockfile.
What this error means
The build "restores cache" but then fails or behaves oddly because the installed dependency set predates the latest lockfile change. The exact-key miss fell through to a prefix fallback, and nothing re-resolved against the new lockfile.
restore_cache
- Searching: deps-v1-{{ checksum "package-lock.json" }} (no hit)
- Found via fallback: deps-v1- (older cache)
# install skipped because node_modules "looked" present -> stale depsCommon causes
Prefix fallback restores an old cache
A broad fallback key like deps-v1- is meant to warm the package cache, but if the job treats a restored node_modules as "already installed", it never updates to the new lockfile.
Install step is conditional on a missing directory
Skipping npm ci when node_modules exists means a fallback-restored, stale node_modules is used as-is instead of reconciled.
Caching node_modules instead of the package cache
Caching node_modules directly makes a partial restore look complete; caching ~/.npm and always running npm ci avoids stale trees.
How to fix it
Always install against the lockfile, cache the package cache
- restore_cache:
keys:
- deps-v1-{{ checksum "package-lock.json" }}
- deps-v1-
- run: npm ci # always reconcile to the lockfile
- save_cache:
key: deps-v1-{{ checksum "package-lock.json" }}
paths: [~/.npm]Never skip install on a cache hit
- Run the deterministic install (
npm ci,poetry install) every job, regardless of restore. - Treat restored caches as a speedup, not a substitute for installing.
- Cache the package manager cache dir, not the resolved module tree.
How to prevent it
- Always run a lockfile-deterministic install, even after a cache hit.
- Cache the package manager cache, not
node_modules. - Use prefix fallbacks only to warm the cache, never to skip installing.