TroubleshootingAugust 13, 2026 7 min read

Failed to Fetch: qué significa y cómo solucionarlo

Failed to fetch significa que la petición nunca llegó al servidor. Las cinco causas más comunes, la solución de cada una y cómo saber cuál es la tuya.

Shabnam Katoch

Shabnam Katoch

Growth Head

Failed to Fetch: qué significa y cómo solucionarlo

El error no dice que tu servidor respondió mal. Dice que tu petición nunca llegó. Esa diferencia es todo lo que necesitas para arreglarlo.

Son las once de la noche y llevas cuarenta minutos revisando el código de tu endpoint.

La consola solo dice esto:

TypeError: Failed to fetch

Y aquí está el detalle que casi todo el mundo pasa por alto. Esa distinción te ahorra la mitad del tiempo de depuración, porque cambia por completo dónde tienes que buscar.

Un 404 no lanza este error. Un 500 tampoco. Cuando el servidor responde, aunque responda mal, fetch() cumple su promesa sin problema y te deja un objeto Response con ok: false. El error que estás viendo es distinto: el navegador ni siquiera pudo entregar la petición, o se negó a dejarte leer la respuesta.

Así que deja de revisar tu controlador. El problema está antes.

Qué significa exactamente el error failed to fetch

fetch() devuelve una promesa. Esa promesa se rechaza con un TypeError únicamente en dos situaciones: cuando la petición no pudo salir o llegar, y cuando el navegador bloqueó tu acceso a la respuesta por política de seguridad.

Todo lo demás, cualquier código de estado entre 200 y 599, se resuelve correctamente.

Por eso este código te engaña:

const res = await fetch(url);
const data = await res.json(); // esto sí revienta con un 404

Si esperabas que fetch lanzara una excepción con un 404, no lo hace. Comprueba siempre res.ok antes de parsear.

Failed to fetch no es un error de tu backend. Es un error de que tu backend nunca se enteró.

Qué lanza y qué no lanza un TypeError: la promesa de fetch se rechaza con CORS bloqueado, servidor caído, contenido mixto, petición cancelada y DNS que no resuelve, porque la petición no llegó o la respuesta fue bloqueada. En cambio se resuelve correctamente con un 404 Not Found, un 500 Internal Server Error, un 403 Forbidden, una respuesta lenta de tres segundos o un JSON malformado en el body, porque el servidor respondió y fetch cumplió su promesa. Comprueba res.ok antes de parsear: const data = await res.json() sí revienta con un 404, pero por .json() sobre una respuesta HTML, no por fetch

Las cinco causas más comunes y cómo solucionar cada una

Ordenadas por frecuencia real, no por orden alfabético.

1. CORS, el sospechoso número uno

Si tu petición sale de un origen y va hacia otro, el navegador exige permiso explícito del servidor. Sin la cabecera Access-Control-Allow-Origin correcta, el navegador descarta la respuesta y tú recibes Failed to fetch.

Lo confuso es que la petición sí llegó al servidor. Puedes verla en tus logs. El bloqueo ocurre después, en el navegador.

Cómo confirmarlo: abre la consola, no la pestaña de red. El mensaje de CORS aparece ahí, en rojo, con el origen exacto que fue rechazado. El TypeError es solo el eco.

La solución está en el servidor, siempre. Añade el origen a Access-Control-Allow-Origin, y si tu petición usa métodos distintos de GET o cabeceras personalizadas, asegúrate de responder también al preflight OPTIONS. Poner mode: "no-cors" en el cliente no arregla nada, solo te devuelve una respuesta opaca que no puedes leer.

CORS explicado en tres pasos. Lo que parece: que la petición desde localhost:3000 nunca salió del navegador y CORS la bloqueó antes de llegar a api.ejemplo.com. Lo que realmente pasó: la petición sí llegó al servidor, que respondió 200 OK y lo registró en sus logs, pero faltaba la cabecera Access-Control-Allow-Origin y el bloqueo ocurrió después, ya en el navegador. La solución: añadir el origen a Access-Control-Allow-Origin en la configuración del servidor y responder al preflight OPTIONS con 200 cuando el método no es simple. Poner mode no-cors no arregla nada, solo devuelve una respuesta opaca que no puedes leer, y el mensaje real aparece en la consola, no en la pestaña de red

2. La URL, el puerto o el DNS

Menos glamuroso, igual de frecuente.

Un localhost:3000 cuando el servidor escucha en el 3001. Una variable de entorno vacía que deja la URL como undefined/api/users. Un dominio mal escrito. Un servicio que se cayó hace veinte minutos.

Prueba el mismo endpoint desde la terminal con curl. Si curl también falla, el problema no está en tu JavaScript y puedes cerrar el editor.

3. Contenido mixto

Tu página se sirve por HTTPS y tu petición apunta a http://. Los navegadores modernos bloquean eso sin preguntar.

Suele aparecer al pasar de desarrollo local a un entorno desplegado, y sorprende porque en local todo funcionaba.

La solución es servir el endpoint por HTTPS. Un certificado autofirmado en tu API tiene el mismo efecto: el navegador rechaza la conexión y tú ves Failed to fetch sin más pistas.

La URL, el puerto o el DNS: los tres fallos habituales son apuntar a localhost:3000 cuando el servidor escucha en el 3001 y recibir ECONNREFUSED, una variable de entorno vacía que deja la URL como undefined/api/users, y un dominio mal escrito que devuelve ENOTFOUND. Si curl también falla, el problema no está en tu JavaScript y puedes cerrar el editor. Debajo, contenido mixto: una página servida por HTTPS que pide http://api.ejemplo.com queda bloqueada sin preguntar, algo que sorprende porque en local, de http a http, todo funcionaba. Sirve el endpoint por HTTPS, y ten en cuenta que un certificado autofirmado provoca el mismo rechazo

4. Algo entre tu navegador y la red

Un bloqueador de anuncios que filtra por patrón de URL. Una extensión de privacidad. Una VPN corporativa. Un firewall que no deja salir ese puerto.

Esta causa tiene una señal muy clara: funciona en ventana de incógnito con las extensiones desactivadas, o funciona en otro navegador, o funciona desde otra red.

Si tu URL contiene palabras como ads, track, analytics o pixel, un bloqueador la va a matar aunque tu endpoint sea completamente legítimo. Es más común de lo que parece.

5. La petición se canceló antes de terminar

Un AbortController que se dispara. Un componente de React que se desmonta y cancela la petición en el cleanup del useEffect. El usuario que recarga la página a mitad de la llamada. Un timeout del lado del cliente.

Todo eso produce el mismo TypeError, y es la causa más difícil de ver porque el código es correcto. Solo se ejecutó en el orden equivocado.

Distingue el caso comprobando error.name === "AbortError" en tu catch antes de tratarlo como fallo real.

Algo entre tu navegador y la red: bloqueadores de anuncios, VPN corporativas y firewalls interceptan la petición antes de que llegue al servidor, y si tu URL contiene ads, track, analytics o pixel, un bloqueador la va a matar aunque el endpoint sea legítimo. El diagnóstico es abrir una ventana de incógnito sin extensiones: si ahí funciona, es una extensión o un bloqueador. Debajo, la petición cancelada antes de terminar: un componente de React que se desmonta hace saltar el AbortController y produce el mismo TypeError. Las causas son el AbortController, el cleanup del useEffect y el usuario que recarga la página. El código es correcto, solo se ejecutó en el orden equivocado, así que comprueba if error.name === AbortError y return antes de tratarlo como fallo real

Cuándo es un problema de red y cuándo es de código

Tres comprobaciones, en este orden, y en menos de dos minutos sabes de qué lado está el problema.

  1. curl desde la terminal. Si falla, es red, servidor o URL, y no es tu JavaScript.
  2. Si curl funciona pero el navegador no, es casi con total seguridad CORS o contenido mixto. El navegador aplica reglas que curl ignora.
  3. Incógnito sin extensiones. Si ahí funciona, tienes un bloqueador o una extensión interfiriendo.

Si curl funciona y el navegador no, el problema es una política del navegador, no una caída del servidor.

Diagrama de decisión para saber de qué lado está el problema en menos de dos minutos. ¿Funciona curl desde la terminal? Si no, es un problema de red, de servidor o de URL, y no es tu JavaScript. Si sí, ¿funciona curl pero no el navegador? Si es así, es casi seguro CORS o contenido mixto, porque el navegador aplica reglas que curl ignora. Si funciona en ambos, revisa la petición exacta. ¿Funciona en incógnito sin extensiones? Si ahí funciona, hay un bloqueador o una extensión interfiriendo; si tampoco funciona, revisa contenido mixto, certificados o cancelación por AbortController

El mismo error en Node.js, que no es el mismo error

Aquí es donde mucha gente se pierde, sobre todo si trabaja con agentes de IA o servicios en el servidor.

En Node.js el mensaje es ligeramente distinto: TypeError: fetch failed. Y en Node no hay CORS, así que puedes descartar la causa número uno de inmediato.

Lo importante es que Node adjunta el motivo real en error.cause. Imprímelo:

catch (e) { console.error(e.cause); }

Ahí verás lo que de verdad pasó: ECONNREFUSED si nada escucha en ese puerto, ENOTFOUND si el DNS no resuelve, o un error de certificado si el TLS falló. Esa propiedad convierte un error genérico en un diagnóstico exacto.

Este es exactamente el caso que aparece cuando un agente local intenta hablar con Ollama y el servicio no está levantado. Lo explicamos a fondo en nuestra guía sobre el error fetch failed con Ollama, que cubre la configuración de host y puerto que casi siempre es la culpable.

El mismo error en el navegador y en Node.js. En el navegador la consola muestra TypeError: Failed to fetch y no te dice por qué, por diseño de seguridad, con CORS, contenido mixto, extensiones, cancelación y red como candidatos. En Node.js el mensaje es TypeError: fetch failed, no existe CORS —así que descartas la causa número uno de inmediato— y Node adjunta el motivo real en error.cause: ECONNREFUSED cuando nada escucha en ese puerto, ENOTFOUND cuando el DNS no resuelve, o un error de certificado si el TLS falló. Imprime console.error(e.cause) en el catch: el caso clásico es un agente local contra Ollama en 127.0.0.1:11434 cuando el servicio no está levantado

Un último apunte antes de que vuelvas a tu consola

Failed to fetch tiene mala fama por ser vago, pero en realidad es honesto. Te está diciendo la única cosa que sabe con certeza: la petición no completó el viaje.

Lo que no te dice es por qué, y eso no es un defecto de la API. Es que el navegador, por diseño de seguridad, no te cuenta los detalles de una petición que bloqueó. Si lo hiciera, cualquier página podría sondear tu red interna.

Así que el mensaje seguirá siendo genérico. La habilidad no está en descifrarlo, está en saber qué comprobar primero.

Si quieres dejar de mantener este tipo de errores por tu cuenta, empieza gratis en BetterClaw. Un agente con todas las funciones, sin tarjeta. El plan Pro cuesta 49 dólares al mes por cinco agentes, conectores ilimitados y 90 días de memoria, con un 20 por ciento de descuento en el plan anual. Precios completos aquí. También puedes pegar cualquier error en nuestro decodificador de errores de agentes y obtener la causa concreta.

Preguntas frecuentes

¿Qué significa el error failed to fetch?

Significa que la petición hecha con fetch() no llegó a completarse a nivel de red, o que el navegador bloqueó el acceso a la respuesta por una política de seguridad. No significa que el servidor devolviera un error, porque un 404 o un 500 se resuelven correctamente y hay que comprobarlos con res.ok.

¿En qué se diferencia de "fetch failed" en Node.js?

Es el mismo tipo de fallo pero en un entorno distinto y con un mensaje ligeramente distinto. En Node no existe CORS, así que esa causa queda descartada, y además el error incluye la propiedad error.cause con el motivo exacto, normalmente ECONNREFUSED, ENOTFOUND o un fallo de certificado.

¿Cómo soluciono un failed to fetch causado por CORS?

La solución siempre está en el servidor, no en el cliente. Añade el origen que hace la petición a la cabecera Access-Control-Allow-Origin y responde correctamente a la petición preflight OPTIONS si usas métodos distintos de GET o cabeceras personalizadas. Usar mode: "no-cors" no lo arregla, solo devuelve una respuesta opaca que no puedes leer.

¿Cuánto tiempo lleva identificar la causa?

Normalmente menos de dos minutos si sigues el orden correcto: prueba con curl, luego compara navegador contra terminal, y luego abre una ventana de incógnito sin extensiones. Esas tres comprobaciones separan un problema de red de uno de configuración del navegador antes de tocar una sola línea de código.

¿Es seguro ignorar este error con un try catch vacío?

No, y es un patrón que esconde caídas reales de servicio durante semanas. Como mínimo distingue el caso de cancelación comprobando error.name === "AbortError", registra el resto con contexto suficiente, e imprime error.cause si estás en Node. Un error silenciado no desaparece, solo se vuelve invisible hasta que un usuario lo reporta.

Tired of debugging?

BetterClaw handles config, OAuth, and deployment. Your agent is live in 60 seconds.

Start free
Tags:failed to fetch que significaque significa failed to fetchfailed to fetch significadofetch failed que significaerror failed to fetch solucionfailed to fetch cors
Share this article
Was this helpful?