---
title: Fix "Exit handler never called" with Node 22.5.0
url: https://photostructure.com/coding/node-22-exit-handler-never-called/
date: 2024-07-21
keywords: Node.js, troubleshooting
---


## 📖 A little background

[PhotoStructure](/) uses [ExifTool](//exiftool.org) to read and write all metadata. ExifTool is written in Perl. PhotoStructure is a TypeScript project that uses ExifTool via the open source [exiftool-vendored](https://github.com/photostructure/exiftool-vendored.js) project.

## 🔴 A broken PR

Tests for exiftool-vendored are run before releases using GitHub Actions, and a recent PR [failed when trying to build against Node.js version 22.x](https://github.com/photostructure/exiftool-vendored.js/actions/runs/9710906344) with a cryptic error:

```
$ run-p lint compile
/bin/sh: 1: run-p: not found
```

This error would happen if `yarn install` or `npm install` wasn't run beforehand. But the task that does that, `yarn ci`, ran successfully, _right_?

{{< figure src="/img/2024/07/gha-fail.jpg" caption="How the color of an icon can waste an hour of your life" >}}

I mean, **there's pretty clearly a happy little checkmark** by the `yarn ci` task right there. No need to click the little disclosure arrow, right?

## 🐛 Is it npm-run-all?

So! Is this an issue with `run-p`? This is a command from [npm-run-all](https://github.com/mysticatea/npm-run-all) which hasn't had a new release since 2018.

Did Node v22 break `npm-run-all`? That'd be a shame: it's a super useful way to run serial and parallel build tasks.

Let's replace the `run-p` call with direct `yarn` calls. And while we're at it, let's see what happened in the `yarn install` task:

{{< figure src="/img/2024/07/mysteries.jpg" caption="...multiple mysteries afoot..." >}}

Wait a minute: there are not one but **three** things that are [odd, inappropriate, confusing, or boring](/go/motto) here. See them?

C'mon, at least try.

...

...

...

...

...

...

OK.

**Oddness #1**: the `yarn install` task's last log entry is step `[2/4] Fetching packages...`. Where's the log entries from step 3 and 4?

**Oddness #2**: `npx rimraf` is warning me that it's installing `rimraf@6.0.1`, which we should have installed already in the prior `yarn install` task.

**Oddness #3**: `tsc` cannot find definitions for `describe`, which we should have installed when `yarn install` pulled in `@types/mocha`.

So all signs seem to point to `yarn install` not working.

## 🔍 Is it yarn classic?

At this point I'm guessing this _must_ be a new interaction with the latest build of Node.js not working with `yarn` classic. I mean, `yarn@1` has been EOL for how many years at this point, so I don't _blame_ it.

OK. So the _obvious_ fix is to switch off of yarn classic. No [big whoop](https://github.com/photostructure/exiftool-vendored.js/commit/bb817442cd9dac8d8c11661be5420557fdeecbdf).

Except that didn't fix it. Are there any other clues around? Let's see if the `npm install` run task worked.

{{< figure src="/img/2024/07/gha-fail-ohhhh.jpg" caption="Is the happy checkmark next to \"npm install\" lying to me?" >}}

## ✅ Finally, a non-spurious error

In case the screenshot is hard to read, here's the error:

```
npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error   <https://github.com/npm/cli/issues>
```

Issues [#7672](https://github.com/npm/cli/issues/7672) and [#7657](https://github.com/npm/cli/issues/7657) track the error we're looking at here.

The pull request that reverts the breakage is [#53904](https://github.com/nodejs/node/pull/53904), and the [postmortem is an interesting read, too](https://github.com/nodejs/node/pull/53934).

And, good news: they've already released v22.5.1 with the revert applied.

[Here are the release notes for v22.5.1, which reference the error we've been fighting](https://nodejs.org/en/blog/release/v22.5.1).

## 🔧 TL;DR: the fix

For my project, the resolution was trivial: [force GitHub Actions to use version 22.5.1 in the build matrix](https://github.com/photostructure/exiftool-vendored.js/commit/6fe3713b44ecb806f5aa08961d77193b059ee915#diff-014228303dff9a1af15f4bbd18401f906380129b10ae2a2c62f8b8be592ff88eR30).

{{< figure src="/img/2024/07/patch.jpg" caption="Hack to force GHA to use 22.5.1 (for now)" >}}

## 📝 In conclusion

This was a textbook case of applying a technique like the "[five whys](https://en.wikipedia.org/wiki/Five_whys)" to an error.

The problem:

1. A PR failed a build.

1. The build failure is nowhere near anything the PR touched, so it may be an external issue, and indeed it is: `run-p: not found`

1. `run-p` is either not in the `$PATH` of the GHA shell, or `yarn` isn't kicking it off correctly with Node v22.

1. `run-p` isn't being installed, either due to some issue with `npm-run-all` or `yarn install` being broken with Node v22.

1. Well, rather than answer that, let's avoid the issue and not use `npm-run-all`, `run-p`, or `yarn`, and directly use `npm` (Node's "native" CLI).

1. Finally after switching to `npm install`, we see `Exit handler never called! This is an error with npm itself` and can look for a resolution.

Thanks to the Node.js team for already having a release with the fix!

