Joonas' blog

How to fix a NPM package mess

published

This is a general guide to fixing NPM package problems. It is based on tens of wasted work days spent digging through random minimized .js files, circular dependency chains, and other weirdnesses. Hopefully it saves you some time.

Try reinstalling first

First step is trying to reinstall packages to make sure nothing there got corrupted. Start from node_modules:

  1. rm -rf node_modules
  2. npm i

This redownloads all packages and reruns post-install scripts, which is often enough to fix many problems. If this does not help, there’s a chance something got corrupted in the lockfile. Try the following:

  1. Find the latest known-to-be-good commit in Git history, where build passes and installs work
  2. Copy package-lock.json from there to current working tree
  • You can use git checkout [working-commit-ref] -- 'package-lock.json' for this
  1. Re-run npm i to update lockfile to current package.json state

And if this does not work either, maybe something has actually broken in the lockfile. You can try to regenerate it like this:

  1. rm package-lock.json (note: this might change the actual in-use dependencies in a wild and somewhat uncontrolled manner; know what you’re doing before committing regenerated lockfile)
  2. npm i

I have missing packages/binaries

Some error messages related to this include Failed to find package "turbo-linux-arm64" on the file system/Error: Cannot find module 'esbuild'/The package "@esbuild/linux-x64" could not be found/Found lockfile missing swc dependencies, run next locally to automatically patch

This generally means that optional dependencies (which are often platform-specific binaries) are missing from the lockfile. This might not get fixed by a simple lockfile removal, because optional dependencies are often dependencies of dependencies and npm randomly breaks those for some reason.

For Next.js + SWC dependencies the solution is simple and reads in the message: run next locally and it will patch the lockfile for you.

For other situations, like esbuild or turbo, the solution is a bit more annoying: you need to install the package in question (e.g. turbo) locally somewhere within the workspace with npm i --save turbo, and then immediately remove the dependency with npm rm turbo. This should modify the lockfile to include the optional dependencies while keeping everything else intact.

Everything is still borked

Presumably, you’re using version control and there exists a (relatively recent) commit where everything works. One method is to return to that known to work version and start applying the changes done in-between one by one to see which of them broke it.

  1. Use git checkout [working-commit-ref] -- '**/package.json' 'package-lock.json' to revert package.json and lockfiles to the known to work version in the working tree
  • Run npm install or build command to ensure that it actually still works locally. If not, something’s wrong there
  1. Select one package-related operation that was done (an upgrade/downgrade/configuration change) and apply it in the working tree
  2. Test if build/install still works
  • Yes -> return to step 2
  • No -> you’ve found the culprit and hopefully it’s nothing too bad