Unexpected token in JSON: qué significa y cómo solucionarlo

Este error indica que el texto que intentó analizar no es JSON. El token que menciona suele revelar exactamente qué recibió en su lugar.

Llama a JSON.parse() o a response.json() y, en lugar de datos, obtiene un SyntaxError. La redacción cambia según el navegador, pero el significado es siempre el mismo: el analizador leyó el texto desde el principio y encontró un carácter que no puede aparecer en ese punto de un JSON válido. El carácter que cita y la posición que indica son las pistas más útiles de las que dispone.

El mismo error en distintos motores

Las versiones recientes de Chrome y Node.js cambiaron la redacción del mensaje, así que encontrará las dos variantes tanto en los resultados de búsqueda como en los logs antiguos.

Dónde lo veráMensaje
Chrome, Edge, Node.js 20 y posterioresUnexpected token '<', "<!DOCTYPE "... is not valid JSON
Versiones antiguas de Chrome y Node.js 18Unexpected token < in JSON at position 0
FirefoxJSON.parse: unexpected character at line 1 column 1 of the JSON data
SafariJSON Parse error: Unrecognized token '<'

«Position 0» o «line 1 column 1» significa que ya el primer carácter era incorrecto. Eso casi siempre indica que la respuesta es otra cosa distinta de JSON, y no una pequeña errata dentro de un documento JSON.

La causa habitual: una página HTML en lugar de JSON

Un < inesperado en la posición 0 es, con diferencia, la variante más frecuente. El código pidió JSON a una API, pero el servidor respondió con una página HTML, y el HTML empieza por <!DOCTYPE html> o por <html>. Estos son los motivos típicos:

  • Una URL incorrecta: una errata o la falta del prefijo /api devuelve la página 404 del sitio.
  • Un error del servidor: el framework genera una página de error 500 en HTML.
  • Una sesión caducada: la petición se redirige a una página de inicio de sesión, y fetch sigue la redirección sin avisar.
  • El comodín de una aplicación de página única: el servidor de desarrollo o el hosting devuelve index.html para cualquier ruta desconocida, con estado 200.
  • Un proxy, una CDN o un firewall intermedio envía su propia página HTML de error o de verificación.

La forma más rápida de confirmarlo es mirar la respuesta en bruto antes de analizarla:

const res = await fetch('/api/items');
console.log(res.status, res.headers.get('content-type'));
const text = await res.text();
console.log(text.slice(0, 200)); // shows the HTML if that is what came back

En el navegador también puede abrir el panel Red (Network) de las herramientas para desarrolladores, hacer clic en la petición y revisar la pestaña Respuesta. Si ve HTML, corrija la URL, la autenticación o el error del servidor: el código que analiza el JSON está bien.

Otros tokens y a qué apuntan

Mensaje actual (mensaje antiguo)Lo que se analizóSolución
"undefined" is not valid JSON (Unexpected token u in JSON at position 0)El valor undefined, por ejemplo una clave de localStorage que no existe o una variable sin asignarCompruebe que el valor existe antes de analizarlo
"[object Object]" is not valid JSON (Unexpected token o in JSON at position 1)Un objeto que ya estaba analizado y que JSON.parse convirtió en cadenaUse el objeto directamente; no lo analice dos veces
Expected property name or '}' in JSON at position 1Comillas simples o claves sin comillas, como en {'a': 1} o {a: 1}Ponga comillas dobles en todas las claves y cadenas
Expected double-quoted property name in JSON at position 8Una coma final, como en {"a": 1,}Elimine la coma que precede a la llave de cierre
Unexpected token 'N', "{"a": NaN}" is not valid JSONNaN, Infinity o undefined dentro de los datosSustitúyalos por null o por un número
Un mensaje que cita en la posición 0 un token invisible o aparentemente vacíoUna marca de orden de bytes (BOM) al principio de un archivo guardado con algunos editores de WindowsGuarde el archivo como UTF-8 sin BOM, o elimine el primer carácter

Analizar datos que ya están analizados

Muchas bibliotecas le entregan objetos ya listos para usar. response.json() ya devuelve un objeto de JavaScript, y lo mismo hace axios en response.data. Si pasa ese objeto a JSON.parse, primero se convierte en la cadena "[object Object]", que falla en la posición 1. Elimine el análisis sobrante:

const data = await res.json();
// JSON.parse(data)  <- fails: data is already an object
console.log(data.items);

Encontrar el fallo dentro de un JSON real

Cuando la posición del error cae en algún punto intermedio, el texto sí es JSON, pero contiene un fallo. Péguelo en el validador de JSON: usa el mismo analizador que su navegador, muestra el mensaje con su posición y su línea, y formatea el documento en cuanto es válido. El error real suele estar justo antes de la posición indicada, por ejemplo una coma que falta entre dos elementos o una comilla que debería haber sido doble.

Cómo protegerse en el código

Comprobar el código de estado y el tipo de contenido antes de analizar convierte un error de sintaxis confuso en un mensaje que explica lo que ocurrió de verdad:

async function getJson(url) {
  const res = await fetch(url);
  const type = res.headers.get('content-type') || '';
  if (!res.ok || !type.includes('application/json')) {
    const body = await res.text();
    throw new Error(`Expected JSON from ${url}, got ${res.status} ${type}: ${body.slice(0, 100)}`);
  }
  return res.json();
}

La misma idea se aplica en el lado del servidor: haga que las rutas de la API devuelvan cuerpos de error en JSON en lugar de páginas de error HTML, y envíelos con Content-Type: application/json. Para el mensaje, muy parecido, que aparece cuando el cuerpo está vacío o cortado, consulte Unexpected end of JSON input.

Preguntas Frecuentes

¿Qué significa «Unexpected token < in JSON at position 0»?

La respuesta empezaba con el carácter <, así que es HTML y no JSON: normalmente una página de error, una página de inicio de sesión o el index.html que se sirve por defecto. Revise la URL de la petición, el código de estado y la cabecera Content-Type.

¿Por qué dice que «"[object Object]" is not valid JSON»?

Pasó un objeto a JSON.parse, que antes lo convirtió en el texto [object Object]. El valor ya está analizado, así que úselo directamente.

¿Puede un validador de JSON encontrar el problema?

Sí, si el texto debe ser JSON. Un validador muestra la posición exacta del primer error. Si el texto es HTML, la solución está en el servidor o en la petición, no en el JSON.