# fetch failed: invalid onError method в Node.js 26

Source: https://ipvolt.com/ru/guides/node-26-invalid-onerror-method
Markdown: https://ipvolt.com/ru/guides/node-26-invalid-onerror-method.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Руководства](https://ipvolt.com/ru/guides.md) / fetch failed: invalid onError method в Node.js 26

Диагностика
Опубликовано: 2026-11-07
9 мин чтения
Автор: ipvolt

В Node.js 26 fetch падает с UND_ERR_INVALID_ARG: invalid onError method, если ему передан диспетчер из старого undici. Как найти эту копию и что исправить.

В Node.js 26 `fetch()` падает с `TypeError: fetch failed` и причиной `invalid onError method` (`UND_ERR_INVALID_ARG`), если ему передан диспетчер, созданный старым npm-пакетом `undici`: обычный `Agent`, keep-alive-агент, защита от SSRF, агент, встроенный в клиентскую библиотеку, или, чаще всего, прокси-агент. Запрос так и не покидает процесс. Каждая версия, строка ошибки и результат ниже получены на стенде 7 ноября 2026 года или взяты из документации и issues по ссылкам.

## Быстрое исправление

```sh
node -p "process.versions.undici"
npm ls undici
```

Если первая команда выводит 8.x, а вторая показывает `undici@5` или `undici@6`, вероятный источник — эта копия. Исправление, которое в наших тестах сработало со всеми версиями undici на обеих линейках Node, — импортировать `fetch` из того же пакета, что создаёт диспетчер: `import { fetch, ProxyAgent } from 'undici'` (исправление A ниже). Если диспетчер нужен только для того, чтобы читать `HTTPS_PROXY`, удалите его и запускайте Node с `--use-env-proxy`.

Проверено на Node.js 26.13.0 (встроенный undici 8.12.2) и 24.22.2 (встроенный undici 7.30.1) с npm undici 5.29.0, 6.29.1, 7.30.2 и 8.12.4 на macOS 26.5.1 arm64, 7 ноября 2026 года. Скрипты и все 166 записанных случаев лежат в [папке стенда](/downloads/node-26-invalid-onerror-method/README.md).

## Ошибка: UND_ERR_INVALID_ARG в err.cause

Это полный вывод минимального примера, показанного ниже: он передаёт `Agent` из npm undici 6.29.1 во встроенный `fetch` Node.js 26.13.0. Путь стенда сокращён до `/lab`:

```text
node:internal/modules/run_main:111
    triggerUncaughtException(
    ^

[TypeError: fetch failed] {
  [cause]: InvalidArgumentError: invalid onError method
      at Agent.dispatch (/lab/u6/node_modules/undici/lib/dispatcher/dispatcher-base.js:198:15)
      at node:internal/deps/undici/undici:15144:57
      at new Promise (<anonymous>)
      at dispatchWithProtocolPreference (node:internal/deps/undici/undici:15144:18)
      at dispatch (node:internal/deps/undici/undici:15142:16)
      at httpNetworkFetch (node:internal/deps/undici/undici:15040:73)
      at httpNetworkOrCacheFetch (node:internal/deps/undici/undici:14912:39)
      at httpFetch (node:internal/deps/undici/undici:14729:43)
      at schemeFetch (node:internal/deps/undici/undici:14637:18)
      at mainFetch (node:internal/deps/undici/undici:14481:30) {
    code: 'UND_ERR_INVALID_ARG',
    Symbol(undici.error.UND_ERR): true,
    Symbol(undici.error.UND_ERR_INVALID_ARG): true
  }
}

Node.js v26.13.0
```

Первая строка `at` называет копию undici, которая выбросила ошибку, — здесь `/lab/u6/node_modules/undici`. С `ProxyAgent` в трассировке появляется ещё одна строка, `at ProxyAgent.dispatch`, а сообщение остаётся тем же. Тот же скрипт на Node.js 24.22.2 вывел `200`. Код, который перехватывает ошибку и логирует только `err.message`, напечатает просто `fetch failed`; причина лежит в `err.cause`.

## Почему Node 26 отвергает диспетчеры старого undici

Встроенный `fetch` — это копия undici, встроенная в Node, а `process.versions.undici` показывает, какая именно. Параметр `dispatcher` передаёт каждый запрос объекту, который вы указали, поэтому две версии undici должны договориться о том, как общаться друг с другом. В undici 8 переименованы колбэки обработчика, которые вызывает диспетчер, например `onError` стал `onResponseError` ([руководство по миграции](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). `fetch` в Node 26 передаёт обработчик только с новыми колбэками. Диспетчер undici 5 или 6 ищет старый `onError`, не находит его и выбрасывает ошибку ещё до открытия соединения. Диспетчеры undici 7 в наших тестах новые колбэки приняли.

Минимальный пример:

```js
import { Agent } from 'undici';

const res = await fetch('https://example.com/', { dispatcher: new Agent() });
console.log(res.status);
```

Те же случаи с `Agent`, `ProxyAgent` и `EnvHttpProxyAgent`, переданными во встроенный `fetch` для отдельного запроса:

| npm undici | Node.js 26.13.0 (undici 8.12.2) | Node.js 24.22.2 (undici 7.30.1) |
| --- | --- | --- |
| 5.29.0 | `invalid onError method` | работает |
| 6.29.1 | `invalid onError method` | работает |
| 7.30.2 | работает | работает |
| 8.12.4 | работает | `invalid onRequestStart method` |

В undici 5.29.0 нет `EnvHttpProxyAgent`; все остальные ячейки верны для всех трёх типов агентов. Старые выпуски вели себя на Node 26 так же: `Agent` и `ProxyAgent` из 5.0.0, 5.28.4, 6.0.0 и 6.21.0 падали с `invalid onError method`, а из восьми опробованных выпусков 7.x, от 7.0.0 до 7.28.0, работали. Последняя строка — то же несовпадение в обратную сторону: `fetch` в Node 24 передаёт обработчик без `onRequestStart`, и диспетчер undici 8 его отвергает.

## Как найти, что тянет старый undici

Запустите обе команды тем же `node` и в том же проекте, где падает код:

```sh
node -p "process.versions.undici"
npm ls undici
```

Первая вывела `8.12.2` на Node 26.13.0 и `7.30.1` на Node 24.22.2. В тестовом проекте с собственным undici 8 и `cheerio@1.0.0` вторая вывела:

```text
my-app@1.0.0 /lab/npm-ls-demo/my-app
├─┬ cheerio@1.0.0
│ └── undici@6.29.1
└── undici@8.12.4
```

`undici@8.12.4` на верхнем уровне — собственная копия проекта. `cheerio@1.0.0` приносит свою `undici@6.29.1`. Запись 5.x или 6.x — это подозреваемый, а не доказательство: ошибка возникает, только если созданный этой копией диспетчер передаётся во встроенный `fetch`. Вопрос решает трассировка: её первая строка `at` показывает путь к копии, которая выбросила ошибку. Инструмент, который вкомпилировал undici в один файл, в `npm ls` не виден вовсе; трассировка Corepack в [corepack#834](https://github.com/nodejs/corepack/issues/834) указывает внутрь `corepack.cjs`.

## Исправления A и B: fetch и диспетчер из одного undici

### Исправление A: fetch из самого undici

Импортируйте `fetch` из того же пакета, что и диспетчер, чтобы обе половины всегда были из одной версии:

```js
import { fetch, ProxyAgent } from 'undici';

const dispatcher = new ProxyAgent(process.env.HTTPS_PROXY);
const res = await fetch('https://example.com/', { dispatcher });
console.log(res.status);
```

На стенде это сработало с undici 5.29.0, 6.29.1, 7.30.2 и 8.12.4 и на Node 26.13.0, и на 24.22.2, с `Agent` и `ProxyAgent`, а также с `EnvHttpProxyAgent` там, где он есть; каждый запрос через прокси дошёл до прокси. Используйте этот вариант в библиотеках, CLI и всём, что работает больше чем на одной линейке Node. `FormData` и другие классы тела запроса берите из того же пакета, что и `fetch` ([документация undici](https://undici.nodejs.org/best-practices/undici-vs-builtin-fetch)). Этим путём пошли исправления Serverless и career-ops и открытый pull request для Vercel CLI, на которые ссылаемся ниже.

### Исправление B: мажорная версия, как в process.versions.undici

```sh
npm install undici@8
```

С undici 8.12.4 встроенный `fetch` Node 26.13.0 принял `Agent`, `ProxyAgent` и `EnvHttpProxyAgent`. На Node 24.22.2 те же диспетчеры упали с `invalid onRequestStart method`, так что это исправление привязывает код к одной линейке Node. undici 8 требует Node.js 22.19.0 или новее ([руководство по миграции](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). undici 7.30.2 на стенде работал на обеих линейках, а Redocly CLI и клиент Qdrant перешли на undici 7; это снимок двух выпусков Node, а не обещание насчёт следующего.

## За прокси: ProxyAgent, EnvHttpProxyAgent, setGlobalDispatcher

`ProxyAgent` и `EnvHttpProxyAgent` из undici 5 или 6 падают точно так же, как обычный `Agent`. `NODE_USE_ENV_PROXY=1` не помогает, пока код по-прежнему передаёт старый диспетчер: `ProxyAgent` из undici 6.29.1 упал с `invalid onError method` на Node 26.13.0 и с этой переменной.

`setGlobalDispatcher()` ломается тише. На Node 26.13.0 глобальный `ProxyAgent` из undici 5.29.0, 6.29.1 или опробованных выпусков 7.x до 7.27.0 (от 7.0.0 до 7.26.0), а также глобальный `EnvHttpProxyAgent` из 6.29.1 не выбросили ошибку. Встроенный `fetch` проигнорировал их и подключился напрямую. При запросе к `https://example.com` глобальный `ProxyAgent` из undici 6.29.1 получил `200`, а в логе прокси не появилось ничего, то есть запрос ушёл с нашего собственного IP; на Node 24.22.2 тот же скрипт прошёл через прокси. undici 7.27.0, 7.28.0, 7.30.2 и 8.12.4 сработали глобально. Ни одна из старых версий не записывает `Symbol.for('undici.globalDispatcher.2')`, где undici 8 [хранит свой глобальный диспетчер](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8); 7.27.0 и новее записывают.

### Исправление C: пусть Node сам читает переменные прокси

Если диспетчер нужен только для того, чтобы отправлять трафик через `HTTPS_PROXY`, удалите его и поручите это Node:

```sh
export HTTPS_PROXY=http://USER:PASS@proxy.example:8080
export NO_PROXY=localhost,127.0.0.1
node --use-env-proxy app.mjs
```

`NODE_USE_ENV_PROXY=1`, флаг `--use-env-proxy` и `NODE_OPTIONS=--use-env-proxy` сработали на Node 26.13.0 и 24.22.2, и для `fetch`, и для `https.get`. Сначала такая возможность появилась для `fetch`, в [этом коммите Node](https://github.com/nodejs/node/commit/ada34bd0ea); [документация Node](https://nodejs.org/api/cli.html#--use-env-proxy) указывает `NODE_USE_ENV_PROXY` начиная с 24.0.0 и `--use-env-proxy` начиная с 24.5.0, а оба — начиная с 22.21.0. Что показал стенд:

- **Читается только при запуске.** `process.env.NODE_USE_ENV_PROXY = '1'` внутри скрипта ничего не дал. Чтобы включить прокси во время работы, вызовите `http.setGlobalProxyFromEnv()` ([добавлен в 24.14.0 и 25.4.0](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv)); он направил через прокси и `fetch`, и `https.get`.
- **Только HTTP_PROXY.** Когда задан только `HTTP_PROXY`, `fetch` использовал его для URL `https://`, а `https.get` подключился напрямую. Задайте `HTTPS_PROXY`.
- **NO_PROXY.** `target.test`, `.test`, `*.test`, `*`, `target.test:8443` и `no_proxy` в нижнем регистре обходили прокси; `target.test:9999` — нет, потому что порт другой. Без `NO_PROXY` запросы к `localhost` и `127.0.0.1` шли через прокси; `NO_PROXY=localhost,127.0.0.1` отправил их напрямую.

`fetch` в Node 26 договорился с целевым сервером стенда о HTTP/2, в том числе внутри туннеля CONNECT, тогда как Node 24 использовал HTTP/1.1. Прокси в обоих случаях видел одну и ту же строку `CONNECT`, и ни один запрос из-за этого не упал.

## Vercel CLI, Corepack, Redocly и другие инструменты вне вашего контроля

Проверено 7 ноября 2026 года:

- **Vercel CLI.** [vercel#17629](https://github.com/vercel/vercel/issues/17629) открыт: при любой заданной переменной прокси версии 59.18.0 и 59.23.1 падают на Node 26.8.2 с `invalid onError method` из встроенного undici 5.29.0 и работают на Node 24.21.0. Исправление, [vercel#17634](https://github.com/vercel/vercel/pull/17634), не влито. Пока оно не попадёт в выпуск, запускайте CLI на Node 24.
- **Corepack.** В [corepack#834](https://github.com/nodejs/corepack/issues/834) описан встроенный `ProxyAgent` undici 6, падающий на Node 26.0.0 и 26.1.0. [Corepack 0.35.0](https://github.com/nodejs/corepack/releases/tag/v0.35.0) отказался от undici и использует поддержку прокси в Node, поэтому задайте `NODE_USE_ENV_PROXY=1`; автор issue подтвердил, что эта связка работает. В установленном нами архиве Node 26.13.0 нет бинарника `corepack` (в 24.22.2 он есть), поэтому проверьте установленную версию командой `corepack --version`.
- **Redocly CLI.** [redocly-cli#3232](https://github.com/Redocly/redocly-cli/issues/3232) касается `login`, `push` и других команд Reunite. [2.62.2](https://github.com/Redocly/redocly-cli/releases/tag/%40redocly/cli%402.62.2) исправил их на Node 26 и перешёл на undici 7.30.0.
- **Serverless Framework.** [4.44.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.44.0) исправил загрузку npm-пакета через прокси на Node 26 ([#13918](https://github.com/serverless/serverless/pull/13918)), а [4.45.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.45.0) — его запросы к API через прокси на Node 26.
- **Клиентские библиотеки, без прокси.** [SocratiCode#154](https://github.com/giancarloerra/SocratiCode/issues/154): `@qdrant/js-client-rest` до 1.19 передаёт `Agent` undici 6 во встроенный `fetch`, а 1.19.0 перешёл на undici 7. [almyty#702](https://github.com/almyty-inc/almyty/pull/702): `Agent` с SSRF-привязкой из undici 6.27.0 падал на Node 26.9.0, и его собственный DNS-lookup так и не вызывался; исправление подняло undici до ^8.11.0. [career-ops#4808](https://github.com/career-ops-hq/career-ops/issues/4808): выход через прокси с `EnvHttpProxyAgent` undici 6 падал на Node 26; v1.36.0 использует с ним собственный `fetch` undici — тот же подход, что и в более раннем [#4787](https://github.com/career-ops-hq/career-ops/pull/4787).

Для любого другого инструмента: обновите его, пока запускайте на Node 24 и сообщите об ошибке с её `cause` и первой строкой `at`.

## Как проверить, что запрос действительно идёт через прокси

Ответ со статусом 200 не доказывает, что его доставил прокси: проигнорированный глобальный диспетчер или совпадение с `NO_PROXY` отправляет запрос напрямую, и доступный сайт всё равно отвечает 200. Сначала посмотрите собственный лог прокси; на стенде каждый запрос через прокси оставлял одну строку `CONNECT` с хостом и портом, а запросы в обход — ни одной. Если доступа к логу прокси нет, спросите сервис, который возвращает ваш IP:

```js
const res = await fetch('https://api.ipify.org?format=json');
console.log(await res.json());
```

Запустите его один раз через вашу настройку прокси, например с заданным `HTTPS_PROXY` и `node --use-env-proxy`, и один раз без неё. Если оба раза выводится один и тот же IP, запрос прошёл мимо прокси.

## Частые вопросы

### Вызывает ли undici 7 ошибку «invalid onError method» в Node.js 26?

В наших тестах нет. `Agent` и `ProxyAgent` из всех опробованных выпусков 7.x, от 7.0.0 до 7.30.2, работали при передаче в отдельный запрос, как и `EnvHttpProxyAgent` из 7.30.2. `setGlobalDispatcher()` из 7.x до 7.27.0 игнорировался без всякой ошибки.

### Почему на Node 24 всё работает, а на Node 26 падает?

В Node 24.22.2 встроен undici 7.30.1, который принимал диспетчеры undici 5 и 6. В Node 26.13.0 встроен undici 8.12.2, который передаёт только новые колбэки.

### Помогает ли NODE_USE_ENV_PROXY=1?

Только после того, как вы удалите старый диспетчер. Пока `ProxyAgent` undici 6 по-прежнему передавался в `fetch`, Node 26 падал так же и с этой переменной.

### У меня «invalid onRequestStart method». Это та же проблема?

Да, только в обратную сторону: диспетчер undici 8 передан в `fetch` более старой линейки Node; мы видели это на Node 24.22.2. Исправление A работает и здесь.

## Похожие руководства

- [Ошибка Node.js TypeError: fetch failed за прокси](/ru/guides/fix-node-fetch-failed-proxy) разбирает все причины в цепочке, а не только эту.
- [Прокси для fetch в Node.js](/ru/guides/nodejs-fetch-proxy) настраивает `ProxyAgent` с аутентификацией и дедлайном.
- [fetch в Node.js игнорирует HTTPS_PROXY](/ru/guides/node-fetch-ignores-https-proxy) объясняет таймаут, который вы получаете без явного включения.
- [Переменные окружения прокси](/ru/guides/proxy-environment-variables) сравнивают, как их читают curl, Requests и Node.
- [Настройки прокси в npm (на английском)](/guides/npm-proxy-settings) помогают провести `npm install undici` через прокси.

**Проверьте исправление через настоящий IP мобильного оператора.** [Мобильный прокси](/pricing) ipvolt — это выделенное устройство в сети оператора, от $9 в день. Укажите его URL в `HTTPS_PROXY` и запустите проверку IP выше с `--use-env-proxy`.

## Источники и дополнительное чтение

- [undici: Migrating from undici 7 to 8 (handler callbacks, global dispatcher)](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)
- [undici: Undici module vs. Node.js built-in fetch](https://undici.nodejs.org/best-practices/undici-vs-builtin-fetch)
- [Node.js CLI: --use-env-proxy](https://nodejs.org/api/cli.html#--use-env-proxy)
- [Node.js CLI: NODE_USE_ENV_PROXY=1](https://nodejs.org/api/cli.html#node_use_env_proxy1)
- [Node.js HTTP: Built-in proxy support and NO_PROXY format](https://nodejs.org/api/http.html#built-in-proxy-support)
- [Node.js HTTP: http.setGlobalProxyFromEnv()](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv)
- [Node.js commit ada34bd: proxy support for fetch under NODE_USE_ENV_PROXY](https://github.com/nodejs/node/commit/ada34bd0ea)
- [vercel/vercel#17629: CLI fails on Node.js 26 with a proxy variable set](https://github.com/vercel/vercel/issues/17629)
- [vercel/vercel#17634: route the CLI through its bundled undici fetch](https://github.com/vercel/vercel/pull/17634)
- [nodejs/corepack#834: bundled undici 6 ProxyAgent on Node.js 26](https://github.com/nodejs/corepack/issues/834)
- [Corepack 0.35.0 release notes](https://github.com/nodejs/corepack/releases/tag/v0.35.0)
- [Redocly/redocly-cli#3232: Reunite commands fail on Node.js 26](https://github.com/Redocly/redocly-cli/issues/3232)
- [Redocly CLI 2.62.2 release notes](https://github.com/Redocly/redocly-cli/releases/tag/%40redocly/cli%402.62.2)
- [serverless/serverless#13918: proxied binary downloads on Node.js 26](https://github.com/serverless/serverless/pull/13918)
- [Serverless Framework 4.44.0 release notes](https://github.com/serverless/serverless/releases/tag/sf-core%404.44.0)
- [Serverless Framework 4.45.0 release notes](https://github.com/serverless/serverless/releases/tag/sf-core%404.45.0)
- [giancarloerra/SocratiCode#154: Qdrant client before 1.19 on Node.js 26](https://github.com/giancarloerra/SocratiCode/issues/154)
- [almyty-inc/almyty#702: SSRF-pinning agent and undici 8](https://github.com/almyty-inc/almyty/pull/702)
- [career-ops-hq/career-ops#4808: proxy egress fails on Node.js 26](https://github.com/career-ops-hq/career-ops/issues/4808)
- [career-ops-hq/career-ops#4787: drive the proxy agent with undici's own fetch](https://github.com/career-ops-hq/career-ops/pull/4787)

## Связанные руководства

- [Исправляем TypeError: fetch failed в Node.js за прокси](https://ipvolt.com/ru/guides/fix-node-fetch-failed-proxy.md)
- [Прокси для fetch в Node.js](https://ipvolt.com/ru/guides/nodejs-fetch-proxy.md)
- [Node fetch игнорирует HTTPS_PROXY: исправляем UND_ERR_CONNECT_TIMEOUT](https://ipvolt.com/ru/guides/node-fetch-ignores-https-proxy.md)

## Об ipvolt

Примеры используют обобщённые настройки прокси со ссылками на оригинальную техническую документацию. Поведение конкретного продукта уточняйте у своего провайдера. ipvolt продаёт мобильные прокси; скоро появятся резидентные — от $2.40/ГБ.

[Читать оригинал на английском](https://ipvolt.com/guides/node-26-invalid-onerror-method.md)

## Подключите свой первый прокси.

Мобильные — от $9 в день. Резидентные — от $2.40 за ГБ, скоро запуск.

[Купить мобильный прокси](https://ipvolt.com/dashboard/mobile)

## Список ожидания резидентных прокси

Оставьте email — сообщим, когда запустим резидентные прокси.

Одно письмо, когда откроется доступ. Больше ничего.

[Записаться](https://ipvolt.com/ru/guides/node-26-invalid-onerror-method#waitlist-closing)

[Конфиденциальность](https://ipvolt.com/privacy)

