npm ci Fails — package.json and package-lock.json Out of Sync
Fix npm ci failures by regenerating the lockfile, committing it, and understanding why ci differs from install.
Symptoms
- npm ci fails with "npm ci can only install packages when your package.json and package-lock.json are in sync"
- Local install works but the CI install fails
- The error lists missing or invalid packages
Possible causes
- A dependency was added or bumped without updating the lockfile
- The lockfile is absent or not committed
- A merge resolved package.json but left a stale lockfile
Diagnosis steps
Regenerate the lockfile locally
npm install && git add package-lock.jsonInterpretation
A normal install rewrites the lock to match package.json, resolving the mismatch.
Verify ci works in a clean checkout
rm -rf node_modules && npm ciInterpretation
A clean ci install passing confirms the lock and manifest now agree.
Root cause
npm ci installs strictly from package-lock.json and refuses to run when the lock does not match package.json. Any manifest change without a matching lock update triggers the error, which is by design to guarantee reproducibility.
Fix
Run npm install to regenerate the lock, commit package-lock.json, and use npm ci in CI exactly as intended; never delete the lock or fall back to install in CI.
Risk note
Switching CI to npm install to bypass the error reintroduces non-reproducible builds and can drift dependency versions.
Verify the fix
Run npm ci in a clean checkout and confirm it completes; verify git status shows no lock changes after install.
Symptoms
This guide profiles the failure behind “npm ci Fails — package.json and package-lock.json Out of Sync”. It walks through the observable symptoms, a reproducible diagnosis path, the underlying root cause, the concrete fix, and how to verify the change and prevent a regression.
Observed symptoms include:
- npm ci fails with “npm ci can only install packages when your package.json and package-lock.json are in sync”
- Local install works but the CI install fails
- The error lists missing or invalid packages
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Regenerate the lockfile locally
npm install && git add package-lock.json
A normal install rewrites the lock to match package.json, resolving the mismatch.
Step 2: Verify ci works in a clean checkout
rm -rf node_modules && npm ci
A clean ci install passing confirms the lock and manifest now agree.
Likely contributors, in order of frequency:
- A dependency was added or bumped without updating the lockfile
- The lockfile is absent or not committed
- A merge resolved package.json but left a stale lockfile
Root Cause
npm ci installs strictly from package-lock.json and refuses to run when the lock does not match package.json. Any manifest change without a matching lock update triggers the error, which is by design to guarantee reproducibility.
The Fix
Run npm install to regenerate the lock, commit package-lock.json, and use npm ci in CI exactly as intended; never delete the lock or fall back to install in CI.
Watch out: Switching CI to npm install to bypass the error reintroduces non-reproducible builds and can drift dependency versions.
# local: regenerate and commit the lock
npm install
npm test
git add package.json package-lock.json
git commit -m "sync lockfile"
# CI: strict, reproducible install
npm ci --no-audit --prefer-offline
Verify and Prevent
Run npm ci in a clean checkout and confirm it completes; verify git status shows no lock changes after install.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.