Los errores son parte de la rutina de cualquier persona desarrolladora, así como saber cómo resolverlos.
Cuando hablamos de Node.js, la mayoría de la información que nos ayuda a resolver errores está dispersa en varios videos y publicaciones en foros. Por eso, podemos tener la sensación de que estamos tardando más de lo necesario en resolver estos problemas. Además, nos encontramos con siglas que, al principio, parecen "misteriosas", como: EADDRINUSE
, ENOTFOUND
, ECONNREFUSED
, entre otras, lo que nos hace pasar aún más tiempo investigando qué significan estas siglas.
Por eso, pensando en facilitar tu día a día, en este artículo entenderemos cómo leer un error, cuáles son los principales errores que vemos en Node.js, las posibles causas de estos errores y cómo podemos resolverlos.
Imagina el siguiente escenario: estás comenzando en la programación, utilizas console.log
y pasas como parámetro una variable que olvidaste crear. Creyendo que todo está bien, ejecutas tu código, como en la imagen a continuación:
Un mar de palabras aparece, parece haber errores incluso en carpetas que ni sabías que existían (node/modules
? Module.load
?) y el miedo de no saber qué hacer aumenta. ¡Pero calma! Vamos a entender por partes lo que está sucediendo en la imagen de arriba.
La primera información que recibimos es el punto donde nuestro código fue finalizado, indicando en qué archivo ocurrió el error y el signo de dos puntos (:), seguido del valor 1, indicando la línea donde ocurrió el error:
A continuación, puedes observar que, en la línea de código que escribimos, hay un acento circunflejo debajo de la palabra nombre
, que es lo que indica la causa del error.
Con esto, ya sabemos que el posible problema está en la palabra nombre
, pero lo que realmente ocurrió lo podemos observar en la línea siguiente:
La información antes de los dos puntos nos indica la clase de error que ocurrió, en este caso, un error de referencia. Después de los dos puntos, tenemos un mensaje de error más descriptivo para el usuario, explicando lo que sucedió: “nombre is not defined”, en español, “nombre no definido”.
A continuación, tenemos lo que llamamos stacktrace del error (rastreo de pila, en español), donde la primera línea se formatea como: , y es seguida por una serie de marcos de pila (cada línea comenzando con "at"). Cada marco informa el camino recorrido hasta llegar al error que se está generando. La palabra “at” aquí tiene el significado de “en” o “en el”, por lo que podemos leer estas líneas como “en el archivo, línea y columna x, en el archivo, línea y columna y, en el archivo, línea y columna z”, etc. Como podemos observar en la imagen a continuación:
Vemos que en la primera línea del stacktrace se indica el archivo en el que ocurrió el error. Los dos puntos seguidos de números nos indican la línea en la que ocurrió el error y el carácter donde comienza el error, por ejemplo, index.js:1:15
. Nota que si cuentas los caracteres de izquierda a derecha, incluidos los espacios, el décimo tercer carácter es la n de la palabra “nombre”.
¡Ahora está mucho más claro! Sabemos que ocurrió un error de referencia porque la variable nombre
no fue creada antes de pasar al console.log
en la primera línea de nuestro código. Es decir, Node.js no tiene referencia de dónde está ese dato para usarlo.
En general, cuando ocurre un error en Node.js, será de una de las cuatro categorías de errores:
Sin embargo, antes de conocer estas clases, es necesario entender que todos los errores de JavaScript y del sistema generados por Node.js son heredados o son instancias de la clase JavaScript Error
. Por lo tanto, todas estas categorías de clases tienen propiedades en común, como:
Nos indica la clase de error generada. En el ejemplo anterior, tuvimos ReferenceError
;
Una cadena (string) que representa un identificador para ese error;
La propiedad message
es la descripción de la cadena del error según se defina (por el usuario, al crear una instancia de error o por el propio Node.js). Este mismo mensaje aparecerá en la primera línea del stacktrace del error.
El punto del código donde la clase Error
fue instanciada, seguido del camino recorrido por el error;
En el ejemplo anterior, otra forma de visualizarlo sería:
try {
console.log(nombre)
} catch (error) {
console.log(`El nombre del error es: ${error.name}\n`)
console.log(`El mensaje de error es: ${error.message}\n`)
console.log(`La pila del error es: ${error.stack}\n`)
}
// usamos \n arriba para saltar una línea extra y visualizar mejor
Y tendríamos como salida:
Es decir, además de leer los errores, es posible "capturar" el contenido de un error (sus propiedades) y con esto crear nuestras propias formas de manejarlo, por ejemplo, crear mensajes personalizados, generar una advertencia para el usuario, entre varias otras opciones.
¿Estás de acuerdo conmigo en que Node.js podría llamar cualquier fallo inesperado un error? Después de todo, si ocurrió un error, lo más justo sería crear la clase Error y tratarlo con los métodos que vimos en el tema anterior.
Pero, pensando en la infinita cantidad de errores que pueden ocurrir, Node.js utiliza el concepto de herencia para crear diferentes clases de errores. Así, queda mucho más claro para la persona desarrolladora qué tipo de error es ese, cada uno con un mensaje personalizado que indica por qué ocurrió el error.
Las clases que vamos a presentar en este tema extienden la clase Error. Es decir, tienen la clase Error como clase base y utilizan sus funcionalidades; sin embargo, cada nueva clase que veremos tiene diferentes aplicaciones.
Esta clase de error es estándar en JavaScript y ocurre cuando pasamos un argumento fuera del rango (o en inglés, range) esperado de una función.
En el ejemplo a continuación, estamos importando el módulo net y utilizando la función createConnection
, que es responsable de crear una conexión socket. No te preocupes si no sabes qué es una conexión socket, en este ejemplo no entraremos en sus funcionalidades.
El primer parámetro de la función createConnection
es el puerto al que se conectará, y los valores aceptados para los puertos van de 0 a 65536. Entonces, si pasamos un valor como -1, recibimos un error informando que este valor está fuera del rango permitido.
Esta clase de error, también estándar en JavaScript, ocurre cuando intentamos acceder a una variable que no está definida. Generalmente, indica errores de tipeo en el código o un programa roto (como algún error en las dependencias de tu proyecto).
Esta clase de error, estándar en JavaScript, ocurre al intentar interpretar código sintácticamente inválido. Es decir, cuando se escribe algo que no está conforme a la sintaxis del lenguaje.
En el ejemplo a continuación, se creó y llamó a la función generandoSyntaxError
en la que, de manera intencional, no se colocó la coma para separar las propiedades del objeto. La regla sintáctica de JavaScript es que las propiedades de un objeto deben ser separadas por comas. Si el desarrollador no sigue esta regla, se recibe un error de sintaxis.
Esta clase de error indica que un argumento proporcionado no es un tipo permitido. Por ejemplo, una función que espera recibir un tipo específico como parámetro, pero recibe otro, sería un TypeError, como se muestra a continuación, donde el método parse
espera una cadena (string), pero recibe un número.
Cuidado para no confundir TypeError (error de tipo) con la palabra "type", que también puede significar "teclear".
El assert es, de forma resumida, un módulo de JavaScript que permite probar nuestras expresiones.
En el ejemplo anterior, importé un método llamado ok
, que verifica si una determinada información tiene el valor true. Si es true, no ocurre nada.
Para probar esta funcionalidad, se creó una función llamada verificaParidade
que retorna true para valores pares y false para valores impares.
Cuando pasamos como parámetro del método ok
la función verificaParidade
con un número par, no ocurre nada (como se espera). Sin embargo, en la línea 13 de la imagen anterior, al pasar a la función un valor que devolverá false (el número 3), el AssertionError entra en acción.
El programa se finaliza y se lanza un AssertionError
con el mensaje que escribimos ("El número debería ser par"), que podemos ver a la derecha de la imagen. Además, podemos observar una indicación del valor actual (actual:false
) y el valor esperado (expected:true
).
En resumen, el AssertionError se mostrará siempre que nuestra verificación del assert falle. Esta es una de las bases del funcionamiento de las llamadas pruebas unitarias.
El SystemError (en español, error de sistema) ocurre cuando cometemos alguna violación del sistema operativo mientras ejecutamos nuestro código, como intentar leer un archivo que no existe.
Mira qué interesante, en la imagen anterior, el SystemError devolvió un objeto con algunas propiedades como errno
, code
, syscall
y path
. Este retorno tiene como objetivo ayudar al desarrollador a entender las características del error que se está recibiendo. ¿Vamos a entender qué significa cada una?
open
, que literalmente es lo que el programa intentó hacer: abrir (open) un archivo.Además de estas propiedades, también encontramos, para la clase SystemError, las siguientes propiedades:
Otro detalle del ejemplo anterior es que el error no muestra el nombre de la clase, SystemError
, en el retorno del error, como se ve en otros ejemplos como TypeError
, AssertionError
, entre otros. En su lugar, vemos la propiedad code
acompañada de un mensaje y la llamada al sistema realizada:
Ya vimos que ENOENT es una cadena que representa un código de error que el sistema operativo nos proporciona. ¿Pero qué significa esto? ¿Existen otras cadenas que representan errores?
Al inicio de nuestro artículo hablamos sobre la pérdida de tiempo que podemos tener al buscar el significado de algunas siglas "misteriosas" que son precisamente indicadores de errores. ¡Ahora vamos conocer algunas de ellas y sus significados!
Pero antes de comenzar, es importante señalar que aquí vamos a prestar especial atención al SystemError, ya que son errores extremadamente comunes mientras desarrollamos una aplicación en Node.js, ¿de acuerdo? ¡Vamos allá!
Todas las E al inicio de las siglas significan "Error" (error).
ENOENT
("No Entity", una traducción al español sería "sin entidad") ocurre cuando no existe la entidad esperada (archivo o directorio) en la ruta que especificamos.
Es más común encontrarlo en una operación con el módulo fs
o al ejecutar un script que espera una estructura de directorios específica.
Para solucionar este error, asegúrate de que proporcionaste la ruta correcta para el archivo o directorio necesario en el código, verificando errores de tipeo o modificando tu código para usar una ruta con el archivo existente. Algunas funciones y métodos, como los utilizados por el módulo fs de Node.js, pueden requerir el uso de rutas absolutas o relativas.
EISDIR ("Is a Directory", en español "es un directorio") ocurre cuando una operación espera un archivo, pero recibe, en la ruta proporcionada, un directorio. Podemos observar esto en la imagen a continuación:
En el ejemplo anterior, Node.js nos indica que estamos realizando una operación ilegal, esto porque intentó hacer una lectura (read) pero no había ningún archivo, solo una carpeta vacía. Por lo tanto, para solucionar el error, debemos proporcionar a nuestra función readFile
una ruta hacia un archivo.
Este error es el inverso de EISDIR
. Esto significa que se proporcionó la ruta de un archivo, el archivo existe (de lo contrario, recibiríamos un error ENOENT
), pero lo esperado era un directorio.
En el ejemplo anterior, Node.js nos indica que estamos intentando abrir un directorio (opendir), pero proporcionamos a la función la ruta de un archivo (texto.txt).
Para evitar este error, verifica en tu código si la ruta proporcionada lleva a un directorio y no a un archivo.
Este error ocurre cuando no podemos establecer una conexión con algún host debido a un error del Sistema de Nombres de Dominio (DNS). Generalmente, esto significa un valor incorrecto del host, que "localhost" no esté correctamente mapeado a 127.0.0.1, o incluso que el dominio esté inactivo o ya no exista.
Si recibe este error, verifique que no haya cometido un error de escritura al ingresar el nombre del dominio y que el dominio exista.
Cuando realizamos una solicitud de conexión HTTP, esperamos un buen tiempo y no obtenemos una respuesta, recibimos este error.
La solución general para este problema es capturar el error y repetir la solicitud hasta que se realice con éxito o se alcance el número máximo de intentos. Si encuentra este error con frecuencia, verifique la configuración del tiempo de espera de la solicitud y, si es posible, elija un valor más adecuado.
A partir del nombre, podemos imaginar que se trata de un error (ya que comienza con E), pero ¿el resto del nombre te da alguna pista sobre qué tipo de error es?
Conn me recuerda bastante a connection (en español, conexión), ¿estás de acuerdo? Y refused es, en español, rechazado. A partir de esto, ¿de qué imaginas que se trata este error?
Si llegaste a la conclusión de que se trata de un error de conexión, ¡pensaste correctamente!
Este error ocurre cuando intentamos conectarnos a una máquina de destino y esta rechaza nuestra solicitud. Generalmente sucede cuando intentamos conectarnos a una dirección que no estaba accesible o a un servicio que está inactivo. Las causas pueden ser varias, pero puedes empezar verificando en tu código si te estás conectando a un servicio existente y en línea, y si tu aplicación tiene los permisos necesarios para realizar esa conexión.
Probablemente ya has entrado en un establecimiento y, cuando necesitaste ir al baño, intentaste abrir la puerta y no pudiste entrar porque ya había otro cliente usándolo. Esta situación es un buen ejemplo de lo que significa este error.
Recibimos este error al iniciar o reiniciar un servidor web, cuando intentamos acceder a un puerto que ya está ocupado por otro servidor.
Una forma rápida de verificar este error es creando un servidor que esté usando un puerto, como en el ejemplo a continuación:
const http = require('http');
const nombreHost = '127.0.0.1';
const puerto = 3000;
const servidor = http.createServer((_, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('¡Hola mundo!');
});
servidor.listen(puerto, nombreHost, () => {
console.log(`Servidor en funcionamiento: http://${nombreHost}:${puerto}/`);
});
Este código está dentro de un archivo index.js
, así que para ejecutarlo en el terminal, escribimos: node index.js
Tendremos como salida el mensaje: Servidor en funcionamiento: http://127.0.0.1:3000/
.
Pero, ¿qué sucede si abrimos otro terminal y ejecutamos el mismo código?
Como debes imaginar, recibiremos un error EADDRINUSE:
Haciendo esto, recibiremos un mensaje informando que la dirección ya está en uso (“address in use”, de ahí la sigla EADDRINUSE
) y también un objeto que indica la llamada al sistema, así como la dirección que ya está en uso, el puerto que intentamos escuchar y demás información.
Este error es similar al EADDRINUSE porque se genera al ejecutar un servidor Node.js en un puerto específico. Generalmente indica un problema de configuración con tu dirección IP, como vincular tu servidor a una IP estática. Tomando el código del ejemplo anterior y cambiándolo a una IP estática, tenemos el error:
Con el mensaje indicando que la dirección informada no está disponible (en inglés, "address not available" - EADDRNOTAVAIL
).
Para resolver este problema, verifica si tienes la dirección IP correcta.
¡Existen varios otros códigos de error de sistema! Hemos listado algunos de los más comunes, pero puedes encontrarlos en la página del manual de Linux si deseas consultar la lista completa.
En este artículo, aprendimos cómo identificar cuándo aparece un error en tu pantalla y cómo solucionar los errores más comunes en Node.js. ¡Puedes utilizar este conocimiento para estructurar y desarrollar mejoras en tus aplicaciones y hacer que tu proceso de trabajo sea más ágil!
Existen varios otros códigos de errores y no tengo dudas de que surgirán otros en el futuro. Por eso, ten la documentación sobre errores de Node.js como tu aliada cuando quieras saber más detalles.
Para saber más sobre Node.js, confira esta formación API con Node.js y Express para aprende a crear aplicaciones JavaScript con Node.js utilizando uno de los frameworks más utilizados actualmente.
Este artículo fue traducido y adaptado por Ingrid Silva
Emerson Laranja Soy monitor en Alura y estudiante de ingeniería en computación (Ufes). Mi dedicación está centrada en el desarrollo de contenidos enfocados en el área de backend, con un enfoque especial en JavaScript y TypeScript. Estoy comprometido a proporcionar una experiencia de aprendizaje envolvente y enriquecedora para todos los estudiantes, contribuyendo así al éxito de sus trayectorias en el mundo del desarrollo web.
Cursos de Programación, Front End, Data Science, Innovación y Gestión.
Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana
Paga en moneda local en los siguientes países
Cursos de Programación, Front End, Data Science, Innovación y Gestión.
Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana
Paga en moneda local en los siguientes países
Cursos de Programación, Front End, Data Science, Innovación y Gestión.
Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana
Puedes realizar el pago de tus planes en moneda local en los siguientes países:
País | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Plan Semestral |
487.37
BOB |
69643.08
CLP |
304279.53
COP |
65.90
USD |
260.58
PEN |
1416.98
MXN |
3077.76
UYU |
65.90
USD |
530.79
GTQ |
34904.68
CRC |
4170.00
DOP |
Plan Anual |
738.82
BOB |
105574.27
CLP |
461267.46
COP |
99.90
USD |
395.03
PEN |
2148.04
MXN |
4665.68
UYU |
99.90
USD |
804.64
GTQ |
52913.17
CRC |
6321.44
DOP |
Plan Anual + Boost |
1035.1
BOB |
145727.7
CLP |
664000.13
COP |
149.9
USD |
562.13
PEN |
3048.07
MXN |
6476.68
UYU |
149.9
USD |
1157.18
GTQ |
80946
CRC |
8394.4
DOP |
Acceso a todos
los cursos
Estudia las 24 horas,
dónde y cuándo quieras
Nuevos cursos
cada semana