npm ci expects a compatible package manifest and lockfile and does not repair them in place. Reproduce the error with the same npm configuration, make the intended dependency update in a controlled checkout and review both files together.
Reproduce the boundary in a disposable fixture
Compare manifest and lockfile changes without using CI to silently update dependencies.
Use a new empty temporary directory for this fixture. The example creates only local test data. Commands marked with example.invalid do not identify a real service.
mkdir demo
cd demo
printf '%s
' '{"name":"ci-fixture","version":"1.0.0"}' > package.json
npm install --package-lock-only --ignore-scripts --no-audit --no-fund --offline
npm ci --ignore-scripts --no-audit --no-fund --offline
mkdir -p ../local-dep
printf '%s\n' '{"name":"local-dep","version":"1.0.0"}' > ../local-dep/package.json
node -e 'const fs=require("node:fs");const p=JSON.parse(fs.readFileSync("package.json"));p.dependencies={"local-dep":"file:../local-dep"};fs.writeFileSync("package.json",JSON.stringify(p))'
if npm ci --ignore-scripts --no-audit --no-fund --offline >ci-error.txt 2>&1; then exit 1; fi
node -e 'const p=require("./package-lock.json");if(p.packages[""].dependencies)process.exit(1);console.log("lock was not rewritten")'
head -n 12 ci-error.txt
Observed result
up to date in 105ms
up to date in 98ms
lock was not rewritten
npm error code EUSAGE
npm error
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm error
npm error Missing: local-dep@1.0.0 from lock file
npm error Missing: local-dep@1.0.0 from lock file
npm error
npm error Clean install a project
npm error
npm error Usage:
npm error npm ci
npm errorWhat the result means
The first clean install uses a consistent dependency-free pair. The manifest is then changed to request a local file dependency not represented in the lock. The second invocation fails and the lock still has no dependency entry. The dependency points to another temporary local directory, and offline mode prevents registry use. Its exact diagnostic text may vary because validation or metadata lookup order can differ across npm releases; the observed boundary is that ci does not fix the lock.
Choose the correction for your workflow
Read the full CI error and preserve the failing manifest, lock, Node/npm versions and project npm configuration. Determine whether a dependency change was intentional or whether the wrong files or workspace were supplied. For an intentional change, regenerate the lock with the expected npm tooling in a controlled checkout, review the diff and test npm ci against that pair. For an accidental manifest edit, restore the intended manifest through the normal review process. Cache clearing does not make incompatible inputs compatible.
Limits and the next check
npm ci can remove an existing node_modules directory, so reproduce it in an appropriate disposable environment instead of a working session you depend on. A failure may instead be peer-resolution, platform, permission, registry or lifecycle related; do not label every install error a lock mismatch. The previous legacy-peer-deps guide covers matching tree-shaping flags; retain that policy when it applies. This guide does not authorize installing an unreviewed dependency or changing repository settings.
Related: Compare the related workflow boundary.
This isolated example was executed on macOS on November 10, 2026 (KST). Available tools: node v26.5.0, git git version 2.39.3 (Apple Git-145), npm 11.17.0, jq jq-1.7.1-apple. Shell fixtures use Bash and repository-path identity uses Python 3. This checks the illustrated contract, not your project, host service or every tool version.