SyntaxError: Unexpected end of JSON input significa que el parser llegó al final de la cadena antes de que la estructura JSON estuviera completa. Los datos se cortaron. Este artículo muestra todas las formas comunes en que pasa y cómo arreglar cada una.
Qué significa el error
JSON.parse() es una máquina de estados. Lee caracteres uno a uno y va rastreando corchetes, llaves y delimitadores de cadena abiertos. Cuando alcanza el final de la entrada todavía «dentro» de algo —— un objeto, un array o una cadena —— lanza:
SyntaxError: Unexpected end of JSON inputEl error no da número de línea ni posición porque el problema es la ausencia de contenido —— no hay nada a lo que señalar.
Causa 1 —— Respuesta de API truncada
La causa más común en el mundo real. El servidor envió un cuerpo JSON grande y la red cortó la conexión antes de tiempo, la respuesta se leyó antes de terminar, o se tocó un límite de buffering de un proxy o CDN.
// Lo que llegó (se cayó la conexión a mitad de la respuesta):
'{"users":[{"id":1,"name":"Ada"},{"id":2,"na'
JSON.parse('{"users":[{"id":1,...') // SyntaxError: Unexpected end of JSON inputArreglo: Comprueba el código HTTP y la cabecera Content-Length. Loguea el tamaño del cuerpo crudo antes de parsear. Si usas fetch, siempre haz await de response.json() en vez de leer response.text() y parsear a mano —— el parser JSON del navegador da un error más claro ante truncado.
// Correcto
const data = await response.json();
// Frágil —— oculta los errores de truncado
const text = await response.text();
const data = JSON.parse(text);Causa 2 —— Objeto o array sin cerrar
El JSON se escribió a mano o lo generó código que olvidó un corchete o llave de cierre.
JSON.parse('{"name":"Ada","plan":"pro"')
// Falta el } de cierre
// SyntaxError: Unexpected end of JSON input
JSON.parse('[1, 2, 3')
// Falta el ] de cierre
// SyntaxError: Unexpected end of JSON inputArreglo: Usa un linter JSON o pega la cadena en JSON Fix —— identifica el delimitador no cerrado y, en modo lenient, puede añadir el corchete que falta automáticamente.
Causa 3 —— Cadena sin cerrar
Un valor de cadena que nunca se cerró con la comilla doble final, a menudo porque el valor mismo contenía una comilla doble sin escapar:
JSON.parse('{"title":"He said "hello" to her"}')
// ^ la comilla sin escapar cierra la cadena antes
// SyntaxError: Unexpected end of JSON input
// Correcto —— escapa las comillas internas con barra invertida:
JSON.parse('{"title":"He said \"hello\" to her"}')Arreglo: Escapa las comillas dobles internas como \", o usa JSON.stringify() para construir el JSON desde el principio en vez de armar cadenas a mano.
Causa 4 —— Cadena vacía
Pasarle una cadena vacía o solo con espacios a JSON.parse() lanza el mismo error —— no hay entrada que parsear.
JSON.parse('') // SyntaxError: Unexpected end of JSON input
JSON.parse(' ') // SyntaxError: Unexpected end of JSON input
JSON.parse() // SyntaxError: Unexpected token u… (undefined casteado a cadena)Pasa a menudo cuando un campo de formulario, una clave de localStorage o una variable de entorno está vacía.
// Guard antes de parsear
const raw = localStorage.getItem('session');
if (!raw) return null;
return JSON.parse(raw);Causa 5 —— Lectura demasiado temprana de respuesta en streaming
Al consumir una API en streaming o un WebSocket, es fácil intentar parsear un chunk antes de que llegue el mensaje completo.
// ❌ Intentar parsear un chunk incompleto
ws.onmessage = (event) => {
const data = JSON.parse(event.data); // puede ser parcial
};
// ✓ Buffer hasta el límite de mensaje (framing a nivel de aplicación)
let buffer = '';
ws.onmessage = (event) => {
buffer += event.data;
if (buffer.endsWith('\n')) { // o comprueba un delimitador conocido
const data = JSON.parse(buffer.trim());
buffer = '';
}
};Diagnosticar truncado: Content-Length y el lector de streaming
Dos técnicas concretas para confirmar si la respuesta se cortó:
- Compara con
Content-Length. Si el servidor lo fijó, puedes detectar una lectura corta directamente:const res = await fetch(url); const expected = Number(res.headers.get('Content-Length') ?? NaN); const text = await res.text(); if (Number.isFinite(expected) && text.length !== expected) { throw new Error(`truncated: got ${text.length} of ${expected} bytes`); }Nota:
Content-Lengthpuede no estar en respuestas chunked/comprimidas. - Lee con el body reader de streaming. Usar
res.body.getReader()te deja observar la llegada chunk a chunk y notar cuándo el stream se cierra a mitad de payload —— el síntoma de una conexión caída o timeout de proxy. El navegador expone el fallo de red subyacente como un rechazo defetchsi el stream aborta; combinándolo con el error del parser lo confirmas.
Checklist rápido de diagnóstico
- Loguea
typeof inputeinput.lengthjusto antes de la llamada a parse. - Si la longitud parece demasiado corta, la respuesta se truncó —— revisa los logs de red.
- Si la longitud es 0, la fuente (API, almacenamiento, variable de entorno) no devolvió nada —— añade un guard.
- Si la longitud parece correcta, pega la cadena en JSON Fix para encontrar el problema estructural.
Recupérate con gracia en producción
function safeParse(text, fallback = null) {
if (!text || !text.trim()) return fallback;
try {
return JSON.parse(text);
} catch {
console.error('JSON parse failed, input length:', text.length);
return fallback;
}
}Preguntas frecuentes
¿Qué causa «Unexpected end of JSON input»?
El parser llegó al final de la cadena mientras todavía estaba dentro de un objeto, array o cadena —— los datos estaban incompletos. La causa más común en el mundo real es una respuesta de API truncada; otras son corchete sin cerrar, cadena sin terminar o cadena vacía.
¿Por qué no hay número de línea ni posición?
Porque el problema es contenido faltante, no un carácter equivocado. No hay nada a lo que señalar —— simplemente se quedó sin entrada antes de cerrar la estructura.
¿Cómo lo arreglo si es una cadena vacía?
Pon un guard antes de parsear: if (!raw || !raw.trim()) return fallback;. Campos de formulario vacíos, claves de localStorage ausentes y variables de entorno sin setear son las fuentes habituales.
¿Cómo lo manejo con gracia en producción?
Envuelve JSON.parse() en un helper safeParse que devuelva un fallback en caso de fallo (ver el snippet de arriba), y loguea la longitud de la entrada para distinguir truncado de estructura malformada. Para el set completo de patrones, ver manejar JSON roto en JavaScript.
Arregla JSON truncado en tu navegador
¿Tienes una cadena JSON rota que necesitas inspeccionar o reparar? JSON Fix en fixjson.org parsea, valida y auto-repara errores estructurales comunes —— corchetes que faltan incluidos —— directamente en el navegador, sin enviar datos a ningún servidor.
- JSON Fix —— repara y formatea JSON inválido
- Arreglar «[object Object] is not valid JSON» —— la guía completa de errores de sintaxis JSON
- Errores Unexpected Token explicados —— la guía hermana para errores de parse a nivel de token
- Manejar JSON roto en JavaScript —— patrones para capturar y recuperarse de todos los errores de parse