
TypeError: Cannot read properties of undefined (reading 'name') es la línea más frecuente en
la consola de un navegador, y una de las que peor se interpreta. Casi todo el que la ve busca lo
que se llama name. Lo que se llama name está bien. El error trata sobre lo que se suponía que
debía contenerlo.
Esa es toda la dificultad de este mensaje en una frase. Nombra la propiedad que se intentaba leer, y no dice nada sobre la variable que resultó estar vacía. Así que la solución nunca está donde señala el mensaje, y el primer minuto de cada investigación se dedica a averiguar de qué está hablando en realidad el mensaje.
Cómo leer el mensaje
Tome el código user.profile.name. Si user existe pero no tiene profile, entonces
user.profile es undefined, y leer .name sobre undefined lanza una excepción. El mensaje
dice (reading 'name'). No dice que falte profile, y name es la única palabra de la
expresión que no es el problema.
Cada navegador lo expresa de forma distinta, algo que importa cuando el mismo error llega contado por tres personas distintas:
- Chrome y Edge:
Cannot read properties of undefined (reading 'name'). Las versiones antiguas decíanCannot read property 'name' of undefined, con el mismo significado. - Firefox:
TypeError: user.profile is undefined, ocan't access property "name", user.profile is undefined. Firefox nombra la expresión que estaba vacía, lo cual es más útil. - Safari:
TypeError: undefined is not an object (evaluating 'user.profile.name'). Safari le da toda la expresión y le deja a usted averiguar qué parte falló.
Tres redacciones, un mismo error. Un equipo que abre incidencias pegando la línea de la consola terminará con tres tickets distintos, y el de Firefox es el único que dice dónde mirar.
Existe un mensaje hermano, Cannot read properties of null, y no es exactamente el mismo error.
null es lo que se obtiene de una búsqueda que se ejecutó y no encontró nada:
document.querySelector('.total') en una página sin ningún elemento .total. undefined es lo
que se obtiene de algo que nunca llegó a asignarse: una propiedad que no existe en el objeto, una
variable declarada y no asignada, una función que no devolvió nada. null suele señalar a la
página; undefined suele señalar a los datos.
De dónde salió el undefined
El mensaje es el mismo en todos los casos. La causa es una de una lista corta, y el nombre de la propiedad entre paréntesis es una pista razonable sobre cuál es.
Los datos todavía no han llegado. La página se renderizó antes de que volviera la solicitud
que la rellena, y el código leyó response.items.length mientras response seguía siendo el
marcador de posición. Este es el caso que aparece en conexiones lentas y no en rápidas, en un
móvil y no en un portátil, para el cliente y nunca para el desarrollador. (reading 'length') y
(reading 'map') son las señales típicas: algo esperaba un array y no recibió nada.
La forma cambió. La API antes devolvía user.profile; ahora solo devuelve user.profile
para las cuentas que han rellenado uno, o cambió el nombre de la clave, o el campo se movió un
nivel más arriba. Nada cambió en el cliente, y el error empezó el día del despliegue de otra
persona. Esta es la versión que llega como “ayer funcionaba”.
La clave se escribe de otra forma. item.userId en el código, item.user_id en la
respuesta. Nada le avisa: JavaScript lee una propiedad que no existe como undefined y sigue
adelante, y el error solo aparece un paso después, cuando algo intenta leer a través de ella.
Es una lista vacía. results[0].title cuando results es []. Código perfectamente
válido, hasta la primera búsqueda que no encuentra ninguna coincidencia. Los datos de prueba rara
vez están vacíos; los datos de producción, a menudo sí.
Algo devolvió nada. Una función con una ruta de código que se olvida del return, una
función async cuyo llamador olvidó hacerle await y obtuvo una promesa en lugar de un valor,
un .find() que no encontró ninguna coincidencia. Todo esto produce undefined y se lo entrega
a la línea siguiente.
El código está minificado. En producción el mensaje dice Cannot read properties of
undefined (reading 'a'), porque el proceso de compilación renombró la propiedad. El número de
línea apunta dentro de una sola línea enorme. Sin un source map, el mensaje ha dejado de decir
nada en absoluto, y lo único que queda es la secuencia de solicitudes y clics que llevó hasta él.
Cómo se ve desde el otro lado
Nada de esto es visible para la persona que lo sufre. Lo que ve es una sección de la página que nunca se rellenó, un botón que no hace nada, un formulario que no se envía. Nada en la página dice “se ha producido un error”, porque el error ocurrió dentro de un script y el script simplemente se detuvo. La línea de la consola existe, en un panel que esa persona nunca ha abierto.
Así que el reporte dice “la página del pedido está en blanco”. Y el desarrollador la reproduce, con una conexión rápida, una cuenta completa y una lista no vacía, y no está en blanco.
- Débil
- La página de pedidos está en blanco para un cliente, no se puede reproducir.
- Mejor
- Consola: TypeError: Cannot read properties of undefined (reading 'items'), orders.js line 214. La solicitud a /api/orders justo antes devolvió 200 con un cuerpo vacío. El cliente todavía no tiene pedidos.
La segunda versión es una solución esperando a suceder. Todo en ella proviene de la página en el momento del fallo: la línea de la consola, la solicitud anterior y la respuesta que se suponía que debía contener los datos. Esa es la evidencia que necesita este error, y es exactamente la evidencia que una persona que mira una página en blanco no puede aportar por su cuenta. Nuestra guía para escribir un buen reporte de errores explica qué pedir; la versión corta es que, para este error, la consola y el registro de red son el reporte, y la descripción es solo un pie de foto.
Session Replay
Extensión gratuita para Chrome. Un clic en la página que está fallando toma la captura de pantalla, junto con la consola y el registro de red, y le entrega un enlace para pegar en el ticket.
Cómo encontrar la causa en las herramientas de desarrollador
Cuando tiene la página delante y el error se reproduce, tres pasos resuelven el problema.
Pausar en excepciones. En el panel Sources de Chrome, el icono de pausa con la opción
“Pause on uncaught exceptions” detiene el script en la línea que lanzó el error, con todas las
variables todavía en su ámbito. Pase el cursor sobre la expresión y verá qué parte de
user.profile.name es undefined, algo que el mensaje nunca le habría dicho.
Mire la solicitud anterior. Cambie a la pestaña Network y busque la respuesta que debería
haber rellenado el objeto. Nueve de cada diez veces la respuesta está ahí: un cuerpo vacío, un
200 con un mensaje de error dentro, una clave con un nombre distinto, o una solicitud que nunca
se disparó porque estaba esperando a otra cosa. El artículo sobre
failed to fetch cubre
el caso en que la propia solicitud falló; este artículo trata el caso en que tuvo éxito pero
devolvió la forma equivocada.
Compruebe el orden de los eventos. Si el error solo aparece a veces, casi siempre es la primera causa mencionada antes: una lectura que se ejecuta antes de que existan los datos. Limite la velocidad de red en la pestaña Network a “Slow 3G” y recargue. Si el error aparece de forma constante, es una carrera de eventos, y la solución es esperar a los datos en lugar de proteger la lectura.
La solución que no es una solución
user?.profile?.name hace que el error desaparezca. No hace que aparezca el perfil. El
encadenamiento opcional convierte un fallo en un undefined silencioso, que después fluye hacia
la página como una cadena vacía, una fila que falta, un botón sin etiqueta, y el error ahora es
invisible para usted y sigue siendo visible para el cliente.
Es la herramienta adecuada cuando la ausencia es legítima: una cuenta que realmente todavía no
tiene perfil. Es la herramienta equivocada cuando la ausencia es el error. La pregunta que hay
que hacerse antes de añadir un ?. es si ese valor debería faltar alguna vez. Si la respuesta es
no, el fallo le estaba diciendo algo, y protegerse así es una forma de no escuchar.
Qué llevarse de todo esto
El mensaje nombra la propiedad que usted pedía y esconde lo que estaba vacío. Léalo como “el paso anterior a este no produjo nada”, y vaya a mirar ese paso: la solicitud, el valor de retorno, el nombre de la clave, la lista que estaba vacía. La solución está siempre antes del número de línea, sin excepción.
Y cuando el reporte llega desde la pantalla de otra persona, la línea de la consola y el registro de red no son contexto del error. Para este error, son el error.