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

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

[Inicio de ipvolt](https://ipvolt.com/es.md) / [Guías](https://ipvolt.com/es/guides.md) / fetch failed: invalid onError method en Node.js 26

Solución de problemas
Publicado: 2026-11-07
9 min de lectura
Por ipvolt

En Node.js 26, fetch falla con UND_ERR_INVALID_ARG: invalid onError method si recibe un dispatcher de un undici antiguo. Cómo encontrar esa copia y corregirlo.

En Node.js 26, `fetch()` falla con `TypeError: fetch failed` y la causa `invalid onError method` (`UND_ERR_INVALID_ARG`) cuando recibe un dispatcher creado por un paquete npm `undici` antiguo: un `Agent` normal, un agente keep-alive, una protección contra SSRF, el agente que incluye una biblioteca cliente o, lo más habitual, un agente de proxy. La petición nunca sale del proceso. Cada versión, mensaje de error y resultado de abajo procede de una ejecución en laboratorio del 7 de noviembre de 2026 o de la documentación y los issues enlazados.

## Solución rápida

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

Si el primer comando imprime 8.x y el segundo muestra `undici@5` o `undici@6`, esa copia es el origen probable. La solución que funcionó con todas las versiones de undici en las dos líneas de Node de nuestras pruebas es importar `fetch` del mismo paquete que crea el dispatcher: `import { fetch, ProxyAgent } from 'undici'` (la solución A, más abajo). Si el dispatcher solo existe para leer `HTTPS_PROXY`, elimínalo y arranca Node con `--use-env-proxy`.

Probado con Node.js 26.13.0 (undici 8.12.2 integrado) y 24.22.2 (undici 7.30.1 integrado), con npm undici 5.29.0, 6.29.1, 7.30.2 y 8.12.4, en macOS 26.5.1 arm64, el 7 de noviembre de 2026. Los scripts y los 166 casos registrados están en la [carpeta del laboratorio](/downloads/node-26-invalid-onerror-method/README.md).

## El error: UND_ERR_INVALID_ARG en err.cause

Esta es la salida completa de la reproducción mínima que aparece más abajo, que pasa un `Agent` de npm undici 6.29.1 al `fetch` integrado de Node.js 26.13.0. La ruta del laboratorio está abreviada como `/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
```

La primera línea `at` nombra la copia de undici que lanzó el error: aquí `/lab/u6/node_modules/undici`. Con un `ProxyAgent`, la traza gana una línea, `at ProxyAgent.dispatch`, y el mensaje es el mismo. El mismo script en Node.js 24.22.2 imprimió `200`. El código que captura el error y registra solo `err.message` imprime simplemente `fetch failed`; el motivo está en `err.cause`.

## Por qué Node 26 rechaza los dispatchers de undici antiguos

El `fetch` integrado es una copia de undici incluida en Node, y `process.versions.undici` dice cuál. La opción `dispatcher` entrega cada petición al objeto que le pasas, así que dos versiones de undici tienen que ponerse de acuerdo en cómo hablan entre sí. undici 8 renombró los callbacks del handler que llama un dispatcher, por ejemplo `onError` pasó a ser `onResponseError` ([guía de migración](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). El `fetch` de Node 26 pasa un handler solo con los callbacks nuevos. Un dispatcher de undici 5 o 6 busca el `onError` antiguo, no lo encuentra y lanza el error antes de abrir una conexión. Los dispatchers de undici 7 aceptaron los callbacks nuevos en nuestras pruebas.

La reproducción mínima:

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

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

Los mismos casos con `Agent`, `ProxyAgent` y `EnvHttpProxyAgent`, pasados por petición al `fetch` integrado:

| 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` | funciona |
| 6.29.1 | `invalid onError method` | funciona |
| 7.30.2 | funciona | funciona |
| 8.12.4 | funciona | `invalid onRequestStart method` |

undici 5.29.0 no tiene `EnvHttpProxyAgent`; todas las demás celdas se cumplieron con los tres tipos de agente. Las versiones antiguas se comportaron igual en Node 26: `Agent` y `ProxyAgent` de 5.0.0, 5.28.4, 6.0.0 y 6.21.0 fallaron con `invalid onError method`, y en las ocho versiones 7.x que probamos, de 7.0.0 a 7.28.0, funcionaron. La última fila es el mismo desajuste a la inversa: el `fetch` de Node 24 pasa un handler sin `onRequestStart`, y un dispatcher de undici 8 lo rechaza.

## Encuentra qué incluye un undici antiguo

Ejecuta los dos comandos con el mismo `node` y en el mismo proyecto que el código que falla:

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

El primero imprimió `8.12.2` en Node 26.13.0 y `7.30.1` en Node 24.22.2. En un proyecto de prueba con su propio undici 8 y `cheerio@1.0.0`, el segundo imprimió:

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

El `undici@8.12.4` de nivel superior es la copia propia del proyecto. `cheerio@1.0.0` trae su propio `undici@6.29.1`. Una entrada 5.x o 6.x es una sospechosa, no una prueba: solo falla si un dispatcher creado por ella llega al `fetch` integrado. La traza lo aclara, porque su primera línea `at` muestra la ruta de la copia que lanzó el error. Una herramienta que compila undici dentro de un único archivo no aparece en `npm ls`; la traza de Corepack en [corepack#834](https://github.com/nodejs/corepack/issues/834) apunta dentro de `corepack.cjs`.

## Soluciones A y B: fetch y dispatcher del mismo undici

### Solución A: usa el fetch del propio undici

Importa `fetch` del mismo paquete que el dispatcher, para que las dos mitades vengan siempre de una sola versión:

```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);
```

En el laboratorio funcionó con undici 5.29.0, 6.29.1, 7.30.2 y 8.12.4 tanto en Node 26.13.0 como en 24.22.2, con `Agent` y `ProxyAgent`, y con `EnvHttpProxyAgent` cuando la versión lo tiene; cada petición por proxy llegó al proxy. Úsala en bibliotecas, CLI y todo lo que se ejecute en más de una línea de Node. Toma `FormData` y las demás clases de cuerpo del mismo paquete que `fetch` ([documentación de undici](https://undici.nodejs.org/best-practices/undici-vs-builtin-fetch)). Las correcciones de Serverless y career-ops y el pull request abierto de Vercel CLI enlazados abajo siguen este camino.

### Solución B: la misma versión mayor que process.versions.undici

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

Con undici 8.12.4, el `fetch` integrado de Node 26.13.0 aceptó `Agent`, `ProxyAgent` y `EnvHttpProxyAgent`. En Node 24.22.2 los mismos dispatchers fallaron con `invalid onRequestStart method`, así que esta solución ata tu código a una sola línea de Node. undici 8 necesita Node.js 22.19.0 o posterior ([guía de migración](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). undici 7.30.2 funcionó en las dos líneas en el laboratorio, y Redocly CLI y el cliente de Qdrant pasaron a undici 7; es una foto de dos versiones de Node, no una promesa sobre la siguiente.

## Detrás de un proxy: ProxyAgent, EnvHttpProxyAgent, setGlobalDispatcher

`ProxyAgent` y `EnvHttpProxyAgent` de undici 5 o 6 fallan exactamente igual que un `Agent` normal. Añadir `NODE_USE_ENV_PROXY=1` no ayuda mientras tu código siga pasando el dispatcher antiguo: un `ProxyAgent` de undici 6.29.1 falló con `invalid onError method` en Node 26.13.0 con la variable definida.

`setGlobalDispatcher()` falla de forma más silenciosa. En Node 26.13.0, un `ProxyAgent` global de undici 5.29.0, 6.29.1 o de las versiones 7.x que probamos anteriores a 7.27.0 (de 7.0.0 a 7.26.0), y un `EnvHttpProxyAgent` global de 6.29.1, no lanzaron ningún error. El `fetch` integrado los ignoró y se conectó directamente. Contra `https://example.com`, un `ProxyAgent` global de undici 6.29.1 obtuvo un `200` mientras el proxy no registraba nada, así que la petición salió desde nuestra propia IP; en Node 24.22.2 el mismo script pasó por el proxy. undici 7.27.0, 7.28.0, 7.30.2 y 8.12.4 funcionaron de forma global. Ninguna de las versiones antiguas escribe `Symbol.for('undici.globalDispatcher.2')`, donde undici 8 [guarda su dispatcher global](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8); 7.27.0 y posteriores sí.

### Solución C: deja que Node lea las variables de proxy

Si el dispatcher solo existe para enviar el tráfico por `HTTPS_PROXY`, elimínalo y deja que lo haga 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`, el flag `--use-env-proxy` y `NODE_OPTIONS=--use-env-proxy` funcionaron en Node 26.13.0 y 24.22.2, para `fetch` y para `https.get`. La opción llegó primero para `fetch`, en [este commit de Node](https://github.com/nodejs/node/commit/ada34bd0ea); la [documentación de Node](https://nodejs.org/api/cli.html#--use-env-proxy) recoge `NODE_USE_ENV_PROXY` desde 24.0.0 y `--use-env-proxy` desde 24.5.0, y ambos desde 22.21.0. Lo que mostró el laboratorio:

- **Solo se lee al arrancar.** Definir `process.env.NODE_USE_ENV_PROXY = '1'` dentro del script no hizo nada. Para activarlo en tiempo de ejecución, llama a `http.setGlobalProxyFromEnv()` ([añadido en 24.14.0 y 25.4.0](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv)); envió por el proxy tanto `fetch` como `https.get`.
- **Solo HTTP_PROXY.** Con solo `HTTP_PROXY` definido, `fetch` lo usó para una URL `https://`, pero `https.get` se conectó directamente. Define `HTTPS_PROXY`.
- **NO_PROXY.** `target.test`, `.test`, `*.test`, `*`, `target.test:8443` y `no_proxy` en minúsculas evitaron el proxy; `target.test:9999` no, porque el puerto es distinto. Sin `NO_PROXY`, las peticiones a `localhost` y `127.0.0.1` pasaron por el proxy; `NO_PROXY=localhost,127.0.0.1` las envió directas.

El `fetch` de Node 26 negoció HTTP/2 con el destino del laboratorio, también dentro del túnel CONNECT, mientras que Node 24 usó HTTP/1.1. El proxy vio la misma línea `CONNECT` en ambos casos, y ninguna petición falló por ello.

## Vercel CLI, Corepack, Redocly y otras herramientas que no controlas

Comprobado el 7 de noviembre de 2026:

- **Vercel CLI.** [vercel#17629](https://github.com/vercel/vercel/issues/17629) está abierto: con cualquier variable de proxy definida, las versiones 59.18.0 y 59.23.1 fallan en Node 26.8.2 con `invalid onError method` desde un undici 5.29.0 incluido y funcionan en Node 24.21.0. La corrección, [vercel#17634](https://github.com/vercel/vercel/pull/17634), no está fusionada. Hasta que una versión la incluya, ejecuta el CLI con Node 24.
- **Corepack.** [corepack#834](https://github.com/nodejs/corepack/issues/834) informa de un `ProxyAgent` de undici 6 incluido que falla en Node 26.0.0 y 26.1.0. [Corepack 0.35.0](https://github.com/nodejs/corepack/releases/tag/v0.35.0) abandonó undici y usa el soporte de proxy de Node, así que define `NODE_USE_ENV_PROXY=1`; quien abrió el issue confirmó que esa combinación funciona. El archivo de Node 26.13.0 que instalamos no trae el binario `corepack` (el de 24.22.2 sí), así que comprueba qué versión instalaste con `corepack --version`.
- **Redocly CLI.** [redocly-cli#3232](https://github.com/Redocly/redocly-cli/issues/3232) cubre `login`, `push` y los demás comandos de Reunite. La [2.62.2](https://github.com/Redocly/redocly-cli/releases/tag/%40redocly/cli%402.62.2) los corrigió en Node 26 y pasó a undici 7.30.0.
- **Serverless Framework.** La [4.44.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.44.0) corrigió la descarga por proxy del paquete npm en Node 26 ([#13918](https://github.com/serverless/serverless/pull/13918)), y la [4.45.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.45.0) corrigió sus peticiones a la API por proxy en Node 26.
- **Bibliotecas cliente, sin proxy de por medio.** [SocratiCode#154](https://github.com/giancarloerra/SocratiCode/issues/154): `@qdrant/js-client-rest` anterior a 1.19 pasa un `Agent` de undici 6 al `fetch` integrado, y la 1.19.0 pasó a undici 7. [almyty#702](https://github.com/almyty-inc/almyty/pull/702): un `Agent` con fijación anti-SSRF de undici 6.27.0 falló en Node 26.9.0 y su lookup de DNS propio nunca se ejecutó; la corrección subió undici a ^8.11.0. [career-ops#4808](https://github.com/career-ops-hq/career-ops/issues/4808): la salida por proxy con un `EnvHttpProxyAgent` de undici 6 fallaba en Node 26; la v1.36.0 lo combina con el `fetch` del propio undici, el mismo enfoque que el anterior [#4787](https://github.com/career-ops-hq/career-ops/pull/4787).

Para cualquier otra herramienta: actualízala, mientras tanto ejecútala con Node 24 e informa del error con su `cause` y la primera línea `at`.

## Comprueba que de verdad pasa por el proxy

Una respuesta con estado 200 no demuestra que la haya transportado el proxy: un dispatcher global ignorado o una coincidencia de `NO_PROXY` envía la petición directa, y un sitio accesible sigue respondiendo 200. Mira primero el propio registro del proxy; en el laboratorio cada petición por proxy dejó una línea `CONNECT` con el host y el puerto, y las que lo evitaron no dejaron ninguna. Si no tienes acceso al registro del proxy, pregunta a un servicio que devuelva tu IP:

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

Ejecútalo una vez con tu configuración de proxy, por ejemplo con `HTTPS_PROXY` definido y `node --use-env-proxy`, y otra sin ella. Si las dos imprimen la misma IP, la petición rodeó el proxy.

## Preguntas frecuentes

### ¿undici 7 provoca «invalid onError method» en Node.js 26?

No en nuestras pruebas. `Agent` y `ProxyAgent` de todas las versiones 7.x que probamos, de 7.0.0 a 7.30.2, funcionaron al pasarlos por petición, y también `EnvHttpProxyAgent` de 7.30.2. `setGlobalDispatcher()` de 7.x anterior a 7.27.0 se ignoró sin ningún error.

### ¿Por qué funciona en Node 24 y falla en Node 26?

Node 24.22.2 incluye undici 7.30.1, que aceptó dispatchers de undici 5 y 6. Node 26.13.0 incluye undici 8.12.2, que solo envía los callbacks nuevos.

### ¿Lo arregla NODE_USE_ENV_PROXY=1?

Solo después de eliminar el dispatcher antiguo. Con un `ProxyAgent` de undici 6 todavía pasado a `fetch`, Node 26 falló igual con la variable definida.

### Veo «invalid onRequestStart method». ¿Es el mismo problema?

Sí, a la inversa: un dispatcher de undici 8 pasado al `fetch` de una línea de Node más antigua; lo vimos en Node 24.22.2. La solución A también funciona ahí.

## Guías relacionadas

- [Corregir TypeError: fetch failed de Node.js detrás de un proxy](/es/guides/fix-node-fetch-failed-proxy) lee todas las causas de la cadena, no solo esta.
- [Usar un proxy con fetch de Node.js](/es/guides/nodejs-fetch-proxy) configura un `ProxyAgent` con autenticación y un plazo máximo.
- [fetch de Node.js ignora HTTPS_PROXY](/es/guides/node-fetch-ignores-https-proxy) explica el timeout que aparece sin la activación explícita.
- [Variables de entorno de proxy](/es/guides/proxy-environment-variables) compara cómo las leen curl, Requests y Node.
- [Configuración de proxy en npm (en inglés)](/guides/npm-proxy-settings) consigue que `npm install undici` pase por un proxy.

**Prueba la solución con una IP real de operador móvil.** Un [proxy móvil](/pricing) de ipvolt es un dispositivo dedicado en una red de operador, desde US$9 al día. Pon su URL en `HTTPS_PROXY` y ejecuta la comprobación de IP de arriba con `--use-env-proxy`.

## Fuentes y lecturas adicionales

- [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)

## Guías relacionadas

- [Corregir TypeError: fetch failed de Node.js detrás de un proxy](https://ipvolt.com/es/guides/fix-node-fetch-failed-proxy.md)
- [Usar un proxy con fetch de Node.js](https://ipvolt.com/es/guides/nodejs-fetch-proxy.md)
- [El fetch de Node ignora HTTPS_PROXY: corrige UND_ERR_CONNECT_TIMEOUT](https://ipvolt.com/es/guides/node-fetch-ignores-https-proxy.md)

## Sobre ipvolt

Los ejemplos usan configuraciones de proxy genéricas, con enlaces a la documentación técnica original. El comportamiento específico de cada producto debe comprobarse con tu proveedor. ipvolt vende proxies móviles; los residenciales llegan pronto, desde US$2.40/GB.

[Leer el original en inglés](https://ipvolt.com/guides/node-26-invalid-onerror-method.md)

## Conecta tu primer proxy.

Móvil desde US$9 al día. Residencial desde US$2.40 por GB, próximamente.

[Comprar un proxy móvil](https://ipvolt.com/dashboard/mobile)

## Lista de espera de proxies residenciales

Déjanos tu correo y te avisaremos cuando los proxies residenciales estén disponibles.

Un correo cuando se abra el acceso. Nada más.

[Unirme a la lista](https://ipvolt.com/es/guides/node-26-invalid-onerror-method#waitlist-closing)

[Privacidad](https://ipvolt.com/privacy)

