Skip to content
Nilay Kabariya

Entry No.062·Fixes·Updated ·4 min read

npm ci EUSAGE: lock file not in sync (6 causes, tested)

npm ci says package.json and package-lock.json aren't in sync. Six causes reproduced on npm 11 and 12, and the line in the error that tells them apart.

The error, verbatim

Jump to the fix ↓
npm error code EUSAGE
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 Missing: is-number@7.0.0 from lock file
✓ Reproduced on Windows 11 Pro

Tested on

npm
11.9.0 / 12.2.0; re-tested on 11.21.1 / 12.2.1
Node
24.14.0
OS
Windows 11 Pro

✓ Last re-run on GitHub Actions · see the run · all repros

Contents
  1. 1. Missing: a dependency the lockfile doesn’t have01
  2. 2. Invalid: a range was edited in package.json02
  3. 3. Missing: a peer dependency (legacy-peer-deps)03
  4. 4. Invalid: after adding overrides04
  5. 5. A workspace dependency in a monorepo05
  6. 6. No lockfile06
  7. What didn’t work07
  8. How this was tested08

npm ci installs exactly what package-lock.json says, and refuses to start if that file doesn’t match package.json. It never updates the lockfile itself, which is the point: in CI you get what was committed or nothing. So the error isn’t about your packages. It’s about the two files disagreeing, and the line after the long message says where:

The line under the message Cause
Missing: is-number@7.0.0 from lock file A dependency was added but the lockfile wasn’t updated
Invalid: lock file's ms@2.1.2 does not satisfy ms@2.1.3 A version range was changed by hand
Missing: react@18.3.1 from lock file, a package you never added The lockfile was made with --legacy-peer-deps
Invalid: …, and you just added overrides An override the lockfile doesn’t reflect
Missing: …, in a monorepo A workspace’s own package.json changed
can only install with an existing package-lock.json There is no lockfile at all

I reproduced each one on Windows 11 with npm 11.9.0 and 12.2.0. Both print the same lines, except that npm 12 no longer mentions npm-shrinkwrap.json.

1. Missing: a dependency the lockfile doesn’t have

The usual one. A dependency went into package.json, by hand, by a merge, or by npm install on a machine whose updated lockfile was never committed. Locally everything works, because npm install quietly fixes the lockfile. CI runs npm ci, which won’t:

npm error code EUSAGE
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 Missing: is-number@7.0.0 from lock file

Rewrite the lockfile from package.json, then commit it:

npm install --package-lock-only

The fix only reaches CI once the new package-lock.json is committed and pushed. Check git status after running it: if the lockfile isn’t listed as changed, you’re looking at a different cause.

2. Invalid: a range was edited in package.json

Changing a version in package.json without reinstalling leaves the lockfile pointing at a version the new range no longer allows. I had ms pinned to 2.1.2, then changed it to ^2.1.3:

npm error code EUSAGE
npm error Invalid: lock file's ms@2.1.2 does not satisfy ms@2.1.3

Same fix: let npm resolve the new range and write it down.

npm install --package-lock-only

3. Missing: a peer dependency (legacy-peer-deps)

This one names a package you never added. I installed react-dom@18.3.1 with --legacy-peer-deps, which tells npm to skip peer dependencies, so react never went into the lockfile. A plain npm ci does install peers, wants react, and can’t find it:

npm error code EUSAGE
npm error Missing: react@18.3.1 from lock file

It happens whenever someone fixes an ERESOLVE on their own machine with --legacy-peer-deps, and CI installs without it.

Make the setting part of the project, so every install uses it. Add an .npmrc next to package.json and commit it:

legacy-peer-deps=true

Passing npm ci --legacy-peer-deps in the CI step also works, but the next teammate who runs npm install without the flag rewrites the lockfile the other way.

4. Invalid: after adding overrides

overrides change which version npm should use, so they have to be in the lockfile too. I added "overrides": { "ms": "2.1.3" } to a project whose lockfile had ms 2.1.2 (via debug):

npm error code EUSAGE
npm error Invalid: lock file's ms@2.1.2 does not satisfy ms@2.1.3

Run an install once so the override is applied and recorded, then commit the lockfile:

npm install

5. A workspace dependency in a monorepo

Workspaces share the root package-lock.json. Adding a dependency to packages/app/package.json by hand doesn’t touch it, and npm ci at the root fails with the same Missing: line:

npm error code EUSAGE
npm error Missing: ms@2.1.3 from lock file

Run the install from the repository root, not inside the workspace, so the root lockfile is the one that gets updated:

npm install

6. No lockfile

Same error code, different message. The lockfile isn’t in the repository, often because .gitignore lists it:

npm error code EUSAGE
npm error The `npm ci` command can only install with an existing package-lock.json or
npm error npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or
npm error later to generate a package-lock.json file, then try again.

Create it, remove it from .gitignore if it’s there, and commit it:

npm install

What didn’t work

How this was tested

npm 11.9.0 (bundled with Node 24.14.0) and npm 12.2.0, on Windows 11 Pro, on October 12, 2026. Each cause ran in a fresh project: I created an in-sync lockfile with npm install, changed one thing, and ran npm ci. Packages came from registry.npmjs.org (ms, is-number, debug, react, react-dom). Every message above is the real output.

November 2, 2026: all six causes, both fixes that didn’t work, and every fix were re-run on npm 11.21.1 and 12.2.1 (Node 24.22.1, GitHub Actions ubuntu-latest). Every message and result matched on both. The script and output are public.

— N.K., end of entry No.062

Useful? Pass it on:Post on XFollow @EmotionalMatter

Related entries

  1. No.006

    Fix: npm ERESOLVE unable to resolve dependency tree (React 19)

    npm ERESOLVE with React 19 or ESLint 10, on npm 11 and 12. Four fixes compared, and why --legacy-peer-deps breaks the next npm ci.

    > npm error code ERESOLVE

    FIXED3 min
  2. No.093

    Fix: bigint Failed to load bindings, pure JS will be used

    bigint: Failed to load bindings, pure JS will be used. Why npm 12 shows it on every install, whether it matters, and how to get the native build back.

    > bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)

    FIXED3 minWindows
  3. No.091

    Fix: npm error code EALLOWREMOTE (and EALLOWGIT), tested

    npm error code EALLOWREMOTE: Fetching packages of type remote have been disabled. Every case reproduced on npm 12, from npx to npm ci, with each fix.

    > npm error code EALLOWREMOTE

    FIXED4 min
  4. No.086

    npm error code EACCES: permission denied, 3 causes tested

    npm error code EACCES with syscall mkdir or open: a global install, a cache that sudo left behind, or Docker. Each reproduced, with the fix that lasts.

    > npm error code EACCES

    FIXED2 min

Post card · Every Sunday

What broke this week.

One email on Sundays: the Node, TypeScript, Python and AI SDK releases that broke builds that week, each one reproduced, with a link to the fix that worked. Never shared, and you can leave any time.

— Nilay

or follow by RSSor on X

By subscribing you agree to the privacy note. One click to leave.

tip: paste the exact error text