Estás mirando un stack trace rojo: SyntaxError: Unexpected token '<', "..." is not valid JSON. O quizás es Unexpected token u in JSON at position 0. De cualquier forma, JSON.parse() se negó a correr y tu código dejó de funcionar. Esta guía explica exactamente qué significa cada variante de este error, por qué pasa, y cómo arreglarlo —— rápido.
Cómo se ve el error realmente
La redacción varía según el motor de JavaScript, pero todas significan lo mismo: el parser se topó con un carácter que no esperaba en una posición específica de tu string.
// V8 (Chrome, Node.js, Edge)
SyntaxError: Unexpected token '<', "<html>..." is not valid JSON
SyntaxError: Unexpected token 'u', "undefined" is not valid JSON
SyntaxError: Unexpected token u in JSON at position 0 // V8 más viejo
SyntaxError: Expected ',' or '}' after property value in JSON at position 42
// Firefox (SpiderMonkey)
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data
// Safari (JavaScriptCore)
SyntaxError: JSON Parse error: Unexpected identifier "undefined"
SyntaxError: JSON Parse error: Single quotes (') are not allowed in JSONLa información clave siempre está en dos partes: qué carácter fue inesperado y dónde. El carácter te dice qué recibió el parser; la posición te dice en qué lugar del string mirar.
Causa 1: el servidor devolvió HTML en vez de JSON
Esta es la causa más común de Unexpected token '<'. Tu fetch o llamada AJAX recibió una página HTML —— normalmente una página 404, un redirect de login, o un error de servidor —— en lugar del JSON que esperabas. El < es la apertura de <!DOCTYPE html> o <html>.
// ❌ Esto crashea con "Unexpected token '<'"
const res = await fetch('/api/user');
const data = await res.json(); // el servidor devolvió HTML 404
// ✅ Comprueba primero el status de la respuesta
const res = await fetch('/api/user');
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const data = await res.json(); Comprueba siempre res.ok (o res.status) antes de llamar a res.json(). También puedes inspeccionar el texto crudo de la respuesta primero:
const text = await res.text();
console.log(text.slice(0, 200)); // mira qué obtuviste de verdad
const data = JSON.parse(text);Causa 2: el valor es undefined
Unexpected token 'u' en la posición 0 casi siempre significa que llamaste a JSON.parse(undefined). El string "undefined" empieza por la letra u, que no es un carácter de inicio JSON válido.
// ❌ la variable nunca se asignó
const raw = localStorage.getItem('settings'); // devuelve null si falta
JSON.parse(raw); // null está bien, pero si raw es undefined por algo...
// ❌ datos async aún no cargados
JSON.parse(this.state.data); // data es undefined en el primer render
// ✅ Guard antes de parsear
if (raw) {
const data = JSON.parse(raw);
} Nota que localStorage.getItem() devuelve null (no undefined) para claves ausentes, y JSON.parse(null) devuelve null sin error. Los culpables habituales son variables de state sin inicializar o un argumento de función ausente.
Causa 3: comillas simples en lugar de dobles
// ❌ SyntaxError: Unexpected token '''
JSON.parse("{'name': 'Ada'}");
// ✅ JSON requiere comillas dobles
JSON.parse('{"name": "Ada"}')Los literales de objeto en JavaScript aceptan comillas simples. JSON no —— todos los strings, incluidas las keys, deben usar comillas dobles. Esto suele pasar cuando alguien serializa datos con la función str() de Python en vez de json.dumps(), o copia un literal de objeto directamente.
Causa 4: coma final
// ❌ SyntaxError: Unexpected token '}'
JSON.parse('{"name": "Ada", "score": 98,}');
// ^ coma final
// ✅
JSON.parse('{"name": "Ada", "score": 98}')JavaScript moderno permite comas finales en arrays y objetos. JSON no. Los archivos de configuración JSON editados a mano son la fuente más común de este error.
Causa 5: keys sin comillas
// ❌ SyntaxError: Unexpected token 'n'
JSON.parse("{name: 'Ada'}");
// ✅
JSON.parse('{"name": "Ada"}') Las keys de objeto en JSON siempre deben ser strings entre comillas dobles. Identificadores desnudos como name son válidos en literales de objeto JavaScript pero no en JSON.
Causa 6: comentarios en el JSON
// ❌ SyntaxError: Unexpected token '/'
JSON.parse(`{
// registro de usuario
"name": "Ada"
}`);
// ✅ Elimina los comentarios antes de parsear (o usa un parser JSONC)
const stripped = raw.replace(///.*$/gm, '').replace(//*[sS]*?*//g, '');
JSON.parse(stripped);JSON no tiene sintaxis de comentarios. Los comentarios se añaden a menudo a archivos de configuración (el formato JSONC), pero el JSON.parse() estándar los rechazará al instante.
Causa 7: BOM o carácter invisible en la posición 0
Si el error dice posición 0 pero el primer carácter visible se ve bien, puede haber una marca de orden de bytes invisible (BOM, U+FEFF) u otro carácter de control antepuesto al string —— típicamente al leer un archivo guardado con codificación UTF-8-BOM en Windows.
// ✅ Quita el BOM antes de parsear
const clean = raw.replace(/^/, '');
JSON.parse(clean);Causa 8: tokens I o N —— Infinity y NaN
Si el error dice Unexpected token I o Unexpected token N, la fuente produjo Infinity, -Infinity, o NaN —— todos válidos en JavaScript pero no en JSON.
// ❌ Error del lado productor
const json = '{"ratio": NaN, "limit": Infinity}';
JSON.parse(json); // Unexpected token N (or I) ...
// ✅ Codifícalos deliberadamente
const safe = JSON.stringify({ ratio: NaN, limit: Infinity });
// → '{"ratio":null,"limit":null}' (nota: con pérdida —— ambos se vuelven null)
// ✅ Sin pérdida: codifica como un string centinela que tú parseas de vuelta
JSON.stringify({ ratio: 'NaN', limit: 'Infinity' });JSON.stringify convierte silenciosamente NaN / Infinity a null. Si necesitas que hagan round-trip, reemplázalos con un string centinela al salir y parseálos de vuelta al entrar.
Cómo encontrar la posición exacta del error
El mensaje de error incluye un número de posición. Úsalo para hacer slice del string y ver exactamente qué hay ahí:
function parseWithContext(text) {
try {
return JSON.parse(text);
} catch (err) {
// Extrae la posición del mensaje de error de V8
const match = err.message.match(/position (\d+)/);
if (match) {
const pos = Number(match[1]);
const snippet = text.slice(Math.max(0, pos - 20), pos + 20);
console.error(`Error near: ..."${snippet}"...`);
console.error(` ${''.padStart(Math.min(pos, 20), ' ')}^`);
}
throw err;
}
}Preguntas frecuentes
¿Qué significa «Unexpected token in JSON»?
Significa que JSON.parse() topó con un carácter que no es válido en ese punto de la gramática. El token nombrado te dice qué se recibió (< = HTML, u = undefined, ' = comilla simple) y la posición te dice dónde mirar.
¿Por qué pasa «Unexpected token '<'» con fetch?
Tu petición devolvió una página HTML —— un 404, un redirect de login o un error de servidor —— en lugar de JSON, y el < es la apertura de la etiqueta HTML. Comprueba response.ok antes de llamar a response.json() y loguea await response.text() para ver qué volvió de verdad.
¿Cómo arreglo «Unexpected token u in JSON at position 0»?
Pasaste undefined a JSON.parse(). Guard el valor primero (if (raw) JSON.parse(raw)) y revisa si hay state sin inicializar o un argumento de función ausente. La variante estrechamente relacionada token o se trata en Unexpected token o in JSON.
¿Cómo encuentro la posición exacta del error?
Lee el número de posición del mensaje de error y haz slice del string alrededor (ve el snippet de arriba), o pega el JSON en JSON Fix, que resalta la línea exacta del problema.
El arreglo más rápido: pega y repara online
Si tienes un string JSON roto y solo necesitas que se arregle ya mismo, JSON Fix maneja automáticamente todas las causas de arriba —— comillas simples, comas finales, keys sin comillas, comentarios, literales de Python y más. Pega tu JSON, haz clic en Repair & Format, y recibe JSON válido y limpio en un solo paso. Todo corre en tu navegador; nada se envía a ningún servidor.
- JSON Fix —— auto-repara JSON roto y muestra la línea exacta del error
- Arreglar errores JSON Unexpected Token —— referencia rápida para cada variante de unexpected token
- Arreglar «[object Object] is Not Valid JSON» —— el error relacionado cuando un objeto se coerciona a string antes de parsear
- JSON Diff —— compara un JSON antes/después para verificar que tu arreglo no cambió nada inesperado