Error: Import failed señala una línea que crea un error. Abrirla explica cómo comunica la aplicación el fallo. Para encontrar qué falló realmente, sigue el cause adjunto hasta el analizador y examina la entrada recibida.

Descarga el laboratorio completo de trazas de JavaScript, descomprímelo y entra en read-javascript-stack-trace. Usa archivos locales y módulos integrados de Node; no requiere instalación ni solicitudes de red. Es un ejemplo construido para este tutorial. La importación lee y analiza registros sin guardarlos. Todos los comandos se ejecutaron con Node.js 22.22.1; usa Node.js 22 o posterior.

Los tres archivos ofrecen un recorrido pequeño para investigar:

Archivo Trabajo Evidencia que examinar
run.mjs Elige una entrada y espera la importación Nombre de entrada, resultado y código de salida
importer.mjs Lee el archivo, llama al analizador y envuelve fallos Bloque try y cause capturado
parser.mjs Pasa texto a JSON.parse Llamada al analizador y texto proporcionado

Ejecuta la entrada fallida y conserva ambas trazas

node run.mjs with-cause

Este comando debe fallar con código 1. La salida siguiente combina stdout y stderr; solo se sustituyó el prefijo de directorio absoluto por file:///lab/. Los nombres, líneas, columnas y texto de error proceden de la ejecución registrada.

Input: records.bad.json
Error: Import failed
    at importRecords (file:///lab/importer.mjs:10:19)
    at async file:///lab/run.mjs:14:19

Caused by:
SyntaxError: Expected double-quoted property name in JSON at position 29 (line 2 column 28)
    at JSON.parse (<anonymous>)
    at parseRecords (file:///lab/parser.mjs:2:15)
    at importRecords (file:///lab/importer.mjs:7:12)
    at async file:///lab/run.mjs:14:19

run.mjs imprime error.stack y error.cause.stack por separado. La primera traza pertenece al envoltorio y la segunda al SyntaxError capturado. Mantén esta distinción al copiar el informe. Un registro que solo guarda el mensaje exterior ha descartado aquí buena parte de la evidencia útil.

En importer.mjs:10:19, los dos últimos números son línea y columna del código. En el mensaje del analizador, «line 2 column 28» se refiere a la entrada JSON. Son coordenadas distintas. Relaciona cada ubicación con su archivo o valor y usa la misma versión de código que produjo la traza.

Abre la línea de construcción y lee la rama catch

Este es todo el importer.mjs de la descarga:

import { readFile } from 'node:fs/promises';
import { parseRecords } from './parser.mjs';

export async function importRecords(input, { preserveCause = true } = {}) {
  try {
    const text = await readFile(input, 'utf8');
    return parseRecords(text);
  } catch (cause) {
    const options = preserveCause ? { cause } : undefined;
    const error = new Error('Import failed', options);
    throw error;
  }
}

La línea 10 crea el envoltorio y la 11 lanza ese objeto existente. La traza exterior empieza en la 10 porque Node registra dónde se construye new Error(). Lanzar después el mismo objeto no desplaza esa ubicación capturada. La documentación de errores de Node.js 22 describe este comportamiento.

También importa el bloque try: pueden fallar tanto readFile como parseRecords y ambos reciben el mismo mensaje exterior. «Import failed» no permite distinguirlos. Por ejemplo, la prueba de archivo ausente obtiene una causa ENOENT en lugar de SyntaxError.

Sigue la causa hasta el analizador y la entrada real

La traza de la causa empieza por JSON.parse. Continúa hasta el primer marco de código que puedes inspeccionar: parser.mjs:2:15.

export function parseRecords(text) {
  return JSON.parse(text);
}

Sigue después text hasta readFile(input, 'utf8'). run.mjs seleccionó records.bad.json, cuyo contenido completo es:

[
  {"id": "tea", "count": 2,}
]

La coma posterior a 2 deja al analizador esperando otro nombre de propiedad. En esa ubicación encuentra }. Ya tienes una entrada, una operación concreta y un fallo reproducible. La línea de construcción del envoltorio era la entrada a la investigación; cambiar su mensaje dejaría este JSON igual.

new Error(message, { cause }) conserva el valor capturado en el nuevo error. Node añadió esta opción en 16.9.0 y está documentada para 22.22.1, usado aquí. El valor puede ser cualquiera, por lo que el manejo general de errores debe comprobar su tipo antes de leer .stack. El impresor del laboratorio comprueba instanceof Error. Consulta la referencia de error.cause.

Elimina la causa y observa qué información desaparece

node run.mjs without-cause

También termina con código 1. La misma entrada sigue fallando, pero ahora la salida acaba así:

Error: Import failed
    at importRecords (file:///lab/importer.mjs:10:19)
    at async file:///lab/run.mjs:14:19

Cause: unavailable

Este modo no pasa la opción cause a new Error. El envoltorio deja de contener el error del analizador. Su traza no permite recuperar la ubicación descartada ni distinguir este fallo del archivo ausente. Necesitarías otra observación, como reproducirlo localmente conservando el error original.

Conservar cause mejora la investigación, pero no corrige la entrada: with-cause sigue fallando, como mostró el primer comando.

Usa los marcos asíncronos como pistas y completa los huecos leyendo

Ambas trazas registradas incluyen at async .../run.mjs:14:19, la función que espera. Cuando falla el análisis, readFile ya se resolvió; su trabajo no aparece, aunque su resultado alimentó al analizador.

La documentación de trazas asíncronas de V8 describe la reconstrucción alrededor de await y determinadas operaciones de Promise, incluidas Promise.all() y Promise.any(). Esos marcos cubren relaciones seleccionadas, no un historial completo de callbacks, temporizadores o E/S. Un marco ausente no demuestra que ese trabajo nunca ocurriera.

El texto de SyntaxError y los marcos disponibles pueden variar según Node/V8. Usa las ubicaciones mostradas para abrir el código correspondiente; esta transcripción no es un formato universal. Las pruebas comprueban propiedades útiles del error y marcos de la aplicación sin comparar toda la cadena de la traza.

Comprueba la hipótesis del reintento contra la entrada

Considera la afirmación «Es un problema temporal de red; reintentar debería solucionarlo». Es una hipótesis didáctica para comprobar, no una cita de un sistema de IA ni un incidente real.

La traza muestra SyntaxError en JSON.parse. El código indica que el analizador recibió bytes de un archivo local. No hay ninguna operación de red y tres intentos con los mismos bytes incorrectos son rechazados. La explicación propuesta no tiene apoyo aquí.

Ejecuta ahora el fixture corregido, que solo elimina la coma final:

node run.mjs fixed

Termina con código 0 e imprime:

Input: records.fixed.json
Parsed records: [{"id":"tea","count":2}]

Después ejecuta las comprobaciones de regresión:

node --test importer.test.mjs

Pasan las nueve pruebas. Cubren la causa del analizador conservada, el envoltorio que la pierde, el fallo repetido con la misma entrada, la entrada corregida, el archivo ausente, la construcción frente al lanzamiento posterior y los tres modos CLI. Los dos comandos de demostración fallidos son fallos esperados, no pruebas de regresión fallidas.

Esto establece la explicación para estos bytes locales. En un importador real, continúa hasta quien produce el texto no válido antes de decidir por qué lo es. El laboratorio comprueba sintaxis JSON y el resultado del ejemplo; no valida un esquema de registros ni persiste una importación.

Lee el código cercano en Yenpo y verifica en el terminal

Abre la carpeta descomprimida en Yenpo y usa la guía de lectura para localizar importer.mjs, parser.mjs y la entrada elegida. Empieza por las líneas indicadas y lee toda la rama catch y el código que proporciona input.

Con un modelo configurado, AI Reader de Yenpo puede ayudar a examinar el recorrido. Una pregunta concreta sería:

Sigue este error Import failed desde su construcción, a través de cause, hasta la entrada de JSON.parse. Cita archivos y líneas. Distingue lo que muestra la traza, lo que establece el código y lo que necesita una ejecución en terminal. Comprueba si reintentar puede cambiar los bytes del ejemplo.

Ejecuta los comandos en tu terminal y compara la salida con la explicación.