Skip to content

"cb() never called? Exit handler never called? I'm having the same problem!"

Gar edited this page Jun 23, 2021 · 1 revision

tl;dr - This error is not one thing, but a category of errors. It means "something broke and we didn't have a way to catch it". We will always need a lot of detail to reproduce an error like this, or we cannot ever fix it. Every instance is unique, and your cb() never called is nothing like any other.

More Details

npm runs a wide variety of different asynchronous operations in the course of doing its work. At the end of all of these operations, we have a single callback which we expect to be called. This callback handles the various errors that we might encounter, writes out the debug log, and in general, tries to be as helpful as possible.

If a Promise rejects without being handled, or an error is thrown without a catch around it, this callback is also invoked to handle the error, by using Node's process.on('uncaughtException') and process.on('unhandledRejection') events.

Sometimes, however, due to bugs either in npm itself, or in one of its dependencies, we might not ever get to an expected end state. That is to say, no error is thrown, no promises rejected, and the process exits as if everything is fine. Without calling the callback.

This is always an error. It means that some flow of control just went off into who-knows-where, without ever saying it was completed. Then, it just... stopped doing stuff, so the process exited.

We track this in npm by using Node's process.on('exit') and process.on('beforeExit') events. If these events fire before the callback that we expect, we raise the cb() not called! error.

This indicates that something is wrong, in a way that we do not have any way of predicting or expecting. It failed in a way that did not even alert us to its failure. Most of the time, this is due to some kind of race conditions with the many streams that we handle and pipe together.

As npm has moved to a more consistent stream implementation with Minipass, and more of its dependencies have moved to Promises rather than manually passing callback functions around, these errors have become less frequent. However, the surface that npm covers is large, and it does a lot of stuff.

The important thing to remember is: every cb() never called error is unique. It is not helpful to find another issue where someone reports this error message, and say "Hey, I'm having this problem too, any word when it'll be fixed?" Fixing theirs might not fix yours, and as a category of problems in computer science, "race conditions and unexpected deadlocks" are not anything we're likely to fix in general any time soon.

If you encounter this:

  • If possible, figure out how to reproduce it. If you can't reproduce it, try to figure out where it happens more often or what's going on when it happens.
  • Gather as much data as you can about your environment: node version, npm version, package.json, package-lock.json, configs, etc. Are you using a custom registry? Does it only happen on a given operating system? We need to know these details!
  • See if you can get it to happen in the latest version of npm that's been released. (You can usually upgrade to the latest stable version by running npm i -g npm@latest.)
  • Share everything you have with us, so we can hopefully dig into it and fix this.
  • Post a new issue at https://github.com/npm/cli/issues, and include all the detail you can.