← All posts

npm pruned your lockfile to your laptop

CI died on a package nobody had heard of. npm had quietly removed every platform variant except the one my Mac needed, and the fix everybody documents makes it worse.

A green build, one dependency added, and then this on CI:

npm error `npm ci` can only install packages when your package.json
npm error and package-lock.json are in sync.
npm error Missing: @emnapi/core@1.11.3 from lock file
npm error Missing: @emnapi/runtime@1.11.3 from lock file

I had never heard of @emnapi/core. I had not installed it. It is a transitive dependency of a WebAssembly build of a native tool, several levels down.

What npm had done

Native packages ship one build per platform as optional dependencies. Your lockfile is supposed to list all of them, so an install on any machine can pick the right one. When npm install runs on a Mac it resolves the tree for a Mac, and it writes that pruned tree back to the lockfile. The Linux and Windows branches are dropped.

Commit it, and CI on Linux asks for a package the lockfile no longer mentions.

The damage is cumulative

This is the part that surprised me. I counted the platform-specific entries for one package as I went:

  • The last green build had 18.

  • After a couple of ordinary installs on my Mac, 16.

  • After running the fix everybody recommends, still 16.

  • After deleting the lockfile and regenerating it from scratch, 1.

Deleting the lockfile is the worst available option, not the best one. It resolves cleanly for the machine you are sitting at and discards everything else.

The fix that everyone documents does not work

The standard advice is npm install --package-lock-only, on the grounds that it resolves from registry metadata rather than from your installed tree. I had this written down in my own notes as the answer. It did not restore anything.

What actually worked

Generate the lockfile on the platform CI uses. Mount a temporary directory containing only package.json and the last known good lockfile, so your real node_modules is not touched:

T=$(mktemp -d); cp package.json "$T"/
git show <last-green-commit>:package-lock.json > "$T"/package-lock.json
docker run --rm --platform linux/amd64 -v "$T":/work -w /work node:24 \
  bash -lc 'npm install --package-lock-only && npm ci --ignore-scripts'
cp "$T"/package-lock.json .

That restored the full set. Then verify on your own machine too, because a lockfile that fixes CI can just as easily break the laptop, and only running both proves it.

One warning worth the paragraph. Do not mount your project directory into that container. npm ci wipes and rebuilds node_modules, and it will happily fill your working copy with Linux binaries. I did that, and spent the next ten minutes wondering why nothing would build locally.

© 2026 Gunnie · Magento & Adobe Commerce Expert