# Lab: fetch failed / invalid onError method on Node.js 26

The scripts and recorded results behind the ipvolt guide
[fetch failed: invalid onError method on Node.js 26](https://ipvolt.com/guides/node-26-invalid-onerror-method).

Recorded on 7 November 2026 on macOS 26.5.1 (Darwin 25.5.0, arm64) with the official Node.js
tarballs v26.13.0 (bundled undici 8.12.2) and v24.22.2 (bundled undici 7.30.1), npm undici 5.29.0,
6.29.1, 7.30.2 and 8.12.4, and older releases for the sweep: 5.0.0, 5.28.4, 6.0.0, 6.21.0, 7.0.0,
7.10.0, 7.16.0, 7.24.8, 7.25.0, 7.26.0, 7.27.0 and 7.28.0. No proxy account and no credentials were
used. Everything except step 5 of `run-all.sh` stays on 127.0.0.1.

## Files

| File | What it does |
| --- | --- |
| `run-all.sh` | Installs each undici version into its own folder, creates a self-signed certificate, starts the proxy and the target, runs the matrix and the small scripts, and writes `results.json` and `outputs/`. |
| `proxy.mjs` | A forward proxy on 127.0.0.1:3128 (CONNECT and absolute-URI HTTP). It appends one JSON line per request to `proxy.log`. The host `target.test` resolves only inside this proxy, so a client that bypasses the proxy fails with `getaddrinfo ENOTFOUND target.test`. |
| `target.mjs` | An HTTPS server on 127.0.0.1:8443 that accepts HTTP/2 and HTTP/1.1 and logs which one each request used to `target.log`. |
| `case.mjs` | One case: `node case.mjs <undici folder or none> <mode> <url>`. Prints one JSON line with the versions and the result, or the error and its `cause`. |
| `matrix.py` | Runs every case on both Node versions, counts new lines in `proxy.log` and `target.log` per case, and writes `results.json`. Python 3 standard library only. |
| `repro.mjs`, `repro-proxy.mjs` | The minimal reproductions from the guide (`Agent` and `ProxyAgent` as `dispatcher`). |
| `fix-a.mjs` | Fix A: `fetch` and `ProxyAgent` from the same undici. |
| `fix-c.mjs` | Fix C: no dispatcher; run with `--use-env-proxy`. |
| `global-ignored.mjs` | `setGlobalDispatcher(new ProxyAgent(...))`, then the built-in `fetch`. |
| `ip-check.mjs` | The IP-echo check from the guide. It is not part of `run-all.sh`, because its output is your public IP. |
| `results.json` | All 166 recorded cases: `environment`, then `cases` with `suite`, `label`, `node`, `builtinUndici`, `npmUndici`, `mode`, `result`, `status` or `error` and `cause`, `proxyHits` (the CONNECT targets the proxy logged) and `targetHits` (the HTTP versions the target saw). |
| `outputs/` | The verbatim output of the small scripts, with the lab path shortened to `/lab`. Each file ends with the exit code and the number of new lines in `proxy.log`. |

## Run it

```sh
# Download the official tarballs from https://nodejs.org/dist/ and unpack them, then:
NODE26=/path/to/node-v26.13.0/bin/node NODE24=/path/to/node-v24.22.2/bin/node sh run-all.sh
```

`run-all.sh` needs `python3`, `openssl`, access to the npm registry and, for step 5, a route to
`https://example.com`. It installs old undici releases on purpose; `npm audit` flags some of them.
Do not copy these versions into an application.

## Suites in results.json

- `main`: `Agent`, `ProxyAgent` and `EnvHttpProxyAgent` from undici 5, 6, 7 and 8, passed per request,
  installed with `setGlobalDispatcher()`, and with undici's own `fetch` (Fix A), on both Node versions.
- `fixC`: no dispatcher, with `NODE_USE_ENV_PROXY=1`, `--use-env-proxy`, `NODE_OPTIONS=--use-env-proxy`,
  lowercase `https_proxy`, `HTTP_PROXY` alone, `http.setGlobalProxyFromEnv()` and a
  `process.env.NODE_USE_ENV_PROXY` set inside the script, for `fetch` and `https.get`.
- `noproxy`: `NO_PROXY` values with `NODE_USE_ENV_PROXY=1`.
- `sweep`: older undici releases on Node 26 only.

## Limits

One machine and OS, two Node releases, one plain HTTP proxy without authentication, one local HTTPS
target. Not tested: Linux and Windows, HTTPS and SOCKS proxies, proxies that require credentials,
TLS-intercepting proxies, Deno and Bun, and the third-party tools named in the guide; what the guide
says about those comes from their issues, pull requests and release notes.
