JavaScript Errors

Manejo de errores en JavaScript

Las cosas fallan. Las redes caen, las entradas te sorprenden, las API cambian. Un buen manejo de errores evita que esos fallos se conviertan en caídas del sistema y usuarios molestos.

intermediate14 min readUpdated 15 sept 2026
js
// api.js
class HttpError extends Error {
  constructor(status) {
    super(`Request failed with status ${status}`);
    this.name = "HttpError";
    this.status = status;
  }
}

try {
  const res = await fetch("/api/data");
  if (!res.ok) throw new HttpError(res.status);
  const data = await res.json();
} catch (error) {
  if (error instanceof HttpError) report(error.status);
  else console.error(error);
}
Tipo base
Error
Lanzar con
throw
Manejar con
try / catch / finally
Extender con
class extends Error
Asíncrono
try/catch + rejected promises
Red de seguridad
Manejadores de errores globales

Practico

Try, catch y finally

Cambia el número para provocar el error y observa el orden de los mensajes.

Try, catch y finally

Cambia el número para provocar el error y observa el orden de los mensajes.

Por que importa

Por qué es importante el manejo de errores

Falla con elegancia

Un error manejado mantiene la aplicación funcionando y muestra al usuario algo útil en lugar de una pantalla en blanco.

Depura más rápido

Los buenos errores llevan un mensaje, un tipo y un stack trace, convirtiendo un misterio en una solución de cinco minutos.

Genera confianza

Una recuperación clara y mensajes honestos hacen que una aplicación se sienta sólida incluso cuando la red no lo es.

La imagen completa

Tres preguntas que plantea cada fallo

Un buen manejo de errores responde a las mismas tres preguntas siempre: qué salió mal, quién debe saberlo y qué sucede a continuación.

Detección

Qué salió mal

Lanza errores precisos y tipados en el punto de fallo en lugar de permitir que un estado incorrecto se propague.

Recuperación

Quién lo maneja

Captura el error donde puedas hacer algo significativo y deja que todo lo demás suba en la jerarquía.

Comunicación

Qué sucede a continuación

Dile al usuario qué puede hacer, registra el detalle para los desarrolladores y mantén la aplicación activa.

Manejo de errores de un vistazo

Las herramientas que utilizarás

Objetos Error

message, name, stack y cause: la estructura integrada de un fallo.

throw

Lanza tus propios errores en el momento en que se rompe una regla.

try / catch

Envuelve código riesgoso y maneja el fallo sin que la aplicación colapse.

finally

Limpieza que se ejecuta independientemente de si el intento tuvo éxito o falló.

Errores personalizados

Subclases de Error que transportan datos específicos del dominio.

Errores asíncronos

Promesas rechazadas y try/catch alrededor de await.

Una breve historia

Cómo JavaScript aprendió a fallar correctamente

  1. 1995

    Errores sobre errores

    Los inicios de JavaScript exponen window.onerror como la única red de seguridad global.

    95
  2. 1999

    Llega try / catch

    ES3 introduce el manejo estructurado de excepciones al lenguaje.

    99
  3. 2015

    Promesas y rechazos

    ES6 convierte los rechazos de promesas no manejados en una nueva clase de fallos a gestionar.

    15
  4. 2021

    error.cause

    Los errores ahora pueden envolver la causa subyacente, preservando el contexto original.

    21
  5. Hoy

    Cultura de error primero

    El tooling, los linters y los frameworks asumen un manejo de errores explícito y tipado.

    Hoy

La guia completa

Manejo de errores en JavaScript: Todo lo que necesitas saber

Por qué los errores son inevitables

Todo programa termina enfrentándose a una situación inesperada: un servidor devuelve un 500, un usuario escribe letras en un campo numérico, falta un archivo o una API de terceros cambia su estructura. El manejo de errores no consiste en prevenir cada fallo, sino en decidir qué sucede cuando ocurre uno.

Los errores bien gestionados mantienen la aplicación en funcionamiento, informan al usuario de manera útil y proporcionan a los desarrolladores los detalles necesarios. Por el contrario, los errores mal gestionados provocan pantallas en blanco, pérdida silenciosa de datos e informes de errores imposibles de reproducir.

El objeto Error

JavaScript tiene un tipo Error integrado, y cada error lanzado suele ser una instancia de este.

// error.js
const error = new Error("Something broke");

error.message; // "Something broke"
error.name;    // "Error"
error.stack;   // the call stack at the point of creation
error.cause;   // an optional underlying error

Existen varias subclases integradas para categorías comunes: TypeError, ReferenceError, RangeError, SyntaxError, URIError y EvalError. Se diferencian principalmente en el nombre y en las situaciones que las provocan, lo que las hace útiles para la depuración y para crear bifurcaciones según el tipo de fallo.

Lanzar errores

Usa throw para señalar que se ha violado una regla. Lanza un objeto Error, nunca un string o un número; solo las instancias de Error incluyen un mensaje, un nombre y un stack trace.

// validate.js
function divide(a, b) {
  if (b === 0) {
    throw new Error("Cannot divide by zero");
  }
  return a / b;
}

Lanzar el error lo antes posible, en el punto exacto donde se rompe una suposición, evita que un estado inválido se propague más profundamente en tu programa. Fallar ruidosamente durante el desarrollo es una ventaja, no un inconveniente.

try, catch y finally

try ejecuta código riesgoso. Si algo lanza una excepción, el control salta a catch. finally se ejecuta en cualquier caso, lo que lo convierte en el lugar ideal para realizar la limpieza.

// try.js
try {
  const data = JSON.parse(input);
  save(data);
} catch (error) {
  console.error("Invalid data:", error.message);
} finally {
  setLoading(false);
}

El parámetro catch es el valor lanzado. JavaScript moderno también admite el optional catch binding cuando no necesitas dicho valor: catch { ... }. Dentro de un bloque catch puedes inspeccionar el error, registrarlo en un log, recuperarte o volver a lanzarlo si no puedes manejarlo.

// rethrow.js
try {
  await loadProfile();
} catch (error) {
  log(error);
  throw error; // let a higher layer decide
}

Clases de error personalizadas

Los errores genéricos pierden sentido a medida que tu aplicación crece. Las clases personalizadas te permiten adjuntar contexto y bifurcar la lógica según el tipo de fallo.

// http-error.js
class HttpError extends Error {
  constructor(status, message) {
    super(message ?? `HTTP ${status}`);
    this.name = "HttpError";
    this.status = status;
  }
}

class ValidationError extends Error {
  constructor(field, message) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

Ahora, quienes llamen a la función pueden reaccionar con precisión:

// handle.js
try {
  await save(form);
} catch (error) {
  if (error instanceof ValidationError) {
    showFieldError(error.field, error.message);
  } else if (error instanceof HttpError && error.status === 401) {
    redirectToLogin();
  } else {
    showGenericError();
  }
}

Esta es la diferencia entre un “algo salió mal” y un “el campo de correo electrónico ya está ocupado”.

Envolviendo errores con cause

A veces quieres añadir contexto sin perder el fallo original. La opción cause preserva la cadena.

// cause.js
try {
  await db.query(sql);
} catch (error) {
  throw new Error("Failed to load orders", { cause: error });
}

El error externo contiene el contexto legible para el usuario, mientras que error.cause mantiene el detalle original para los logs y la depuración.

Errores en código asíncrono

El código asíncrono tiene dos rutas de fallo adicionales. Con async/await, try/catch funciona exactamente igual que en el código síncrono.

// async.js
async function load() {
  try {
    const res = await fetch("/api/data");
    if (!res.ok) throw new HttpError(res.status);
    return await res.json();
  } catch (error) {
    console.error("Load failed:", error);
    throw error;
  }
}

Sin await, adjunta un manejador a la promesa:

// promise.js
fetch("/api/data")
  .then((res) => res.json())
  .catch((error) => console.error(error));

Una promesa rechazada sin un manejador se convierte en un unhandled rejection. En los navegadores, esto genera una advertencia; en Node.js, puede terminar el proceso. Maneja siempre los rechazos, aunque sea solo para registrarlos y volver a lanzarlos.

Redes de seguridad globales

Incluso con un código cuidadoso, algo se escapará. Los manejadores globales capturan lo que pasaste por alto para que la aplicación pueda reportarlo en lugar de morir silenciosamente.

// global.js
window.addEventListener("error", (event) => {
  reportToServer(event.error);
});

window.addEventListener("unhandledrejection", (event) => {
  reportToServer(event.reason);
});

En Node.js los equivalentes son process.on("uncaughtException") y process.on("unhandledRejection"). Trata estos manejadores como el último recurso para el registro de logs y el cierre controlado (graceful shutdown), no como un sustituto para manejar los errores donde ocurren.

Valida antes de lanzar

No todos los problemas son excepcionales. Las condiciones esperadas —una entrada vacía, un campo opcional faltante, una búsqueda sin resultados— se gestionan mejor mediante validación que con excepciones.

// guards.js
function formatName(user) {
  if (!user?.name) return "Anonymous";
  return user.name.trim();
}

Reserva las excepciones para situaciones genuinamente inesperadas o irrecuperables. Utilizarlas para el flujo de control ordinario hace que el código sea más lento y más difícil de seguir.

Comunicación con los usuarios

Un mensaje de error técnico es para los desarrolladores. Los usuarios necesitan saber qué sucedió y qué pueden hacer a continuación.

  • Mantén los mensajes cortos y humanos: “No pudimos guardar tus cambios. Verifica tu conexión e inténtalo de nuevo”.
  • Evita la jerga técnica, los stack traces y los códigos de estado raw en la interfaz.
  • Proporciona un siguiente paso: reintentar, volver atrás, contactar al soporte o continuar sin conexión.
  • Registra el detalle completo —mensaje, stack, contexto— para que el equipo de soporte pueda investigar.

Mejores prácticas

  • Lanza objetos Error, nunca strings.
  • Captura errores solo donde puedas recuperarte o añadir contexto útil.
  • Usa clases de error personalizadas para fallos específicos del dominio.
  • Envuelve los errores con cause en lugar de descartar el original.
  • Maneja siempre las promise rejections.
  • Añade handlers globales como red de seguridad final y registra los logs en un servicio real.
  • Valida las condiciones esperadas en lugar de lanzar errores.
  • Mantén los mensajes para el usuario separados de los diagnósticos para el desarrollador.
  • Escribe tests para los flujos de fallo, no solo para el happy path.

Errores comunes

  • Silenciar errores con un bloque catch vacío.
  • Lanzar strings y perder el stack trace.
  • Capturar un error y devolver un valor por defecto que oculta un bug real.
  • Olvidar manejar promesas rechazadas.
  • Mostrar mensajes de error sin procesar a los usuarios.
  • Usar excepciones para el flujo de control ordinario.
  • Asumir que try/catch alrededor de un ejecutor de promesa captura errores asíncronos; no es así.

Próximos pasos

Los errores son el punto donde el código asíncrono y la Fetch API se encuentran con la realidad. Combina estos patrones con el DOM para renderizar estados amigables, y repasa los fundamentos de JavaScript cada vez que un TypeError te recuerde que undefined no es una función.

Lanzamiento de errores

Lanza siempre objetos Error. Estos llevan un stack trace y un mensaje; las cadenas de texto no llevan ninguno de los dos.

Preferir
if (!user) {
  throw new Error("User not found");
}
Evitar
if (!user) {
  throw "User not found";
}

Esperado vs excepcional

Valida las condiciones esperadas; reserva try/catch para cosas que no puedes predecir.

Preferir
if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}
Evitar
try {
  JSON.parse(input);
} catch {
  // swallowing every error hides bugs
}

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Error Handling?

Nuestro tutorial interactivo te guia a traves de Error Handling paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.