"Unexpected token o in JSON at position 1" — qué significa realmente
Este error casi nunca significa que tu JSON esté mal. Significa que llamaste a JSON.parse con algo que nunca fue una cadena JSON — y la letra del mensaje te dice exactamente qué le pasaste.
Si estás mirando un "Unexpected token o in JSON at position 1", tu JSON probablemente está perfecto. Este error significa que JSON.parse recibió un valor que ya era un objeto de JavaScript, no una cadena de texto JSON. Es uno de los mensajes de error más engañosos de JavaScript, porque señala a los datos cuando el fallo está en la llamada.
De dónde sale la "o"
JSON.parse solo acepta una cadena. Si le pasas un objeto, JavaScript lo convierte silenciosamente a texto primero — y cualquier objeto plano se convierte en el texto literal "[object Object]". El parser empieza entonces a leer ese texto: la posición 0 es "[", una forma perfectamente válida de empezar un array JSON, así que continúa. La posición 1 es "o", que no es un valor, ni una clave, ni un corchete válido. De ahí: unexpected token o, en la posición 1. La "o" de la que te avisa es la segunda letra de la palabra "object".
Las tres situaciones que lo provocan
La más común con diferencia es el doble parseo. Métodos como res.json() de fetch o axios ya parsean el cuerpo de la respuesta por ti, así que llamar a JSON.parse sobre el resultado parsea algo que ya es un objeto. La segunda es pasar un objeto directamente a JSON.parse cuando en realidad querías JSON.stringify — son fáciles de intercambiar cuando vas rápido. La tercera es leer de un almacén como localStorage donde una escritura anterior guardó un objeto sin stringificarlo, así que el valor almacenado es el texto literal "[object Object]" y fallará para siempre hasta que lo borres.
Los errores hermanos, y qué te dice cada letra
El carácter que aparece en el mensaje es un diagnóstico preciso, así que léelo en vez de pasarlo por alto. "Unexpected token <" significa que recibiste HTML, no JSON — casi siempre una página de error 404 o 500, una redirección al login, o la intercepción de un proxy, y el fallo real está en la petición, no en el parseo. "Unexpected end of JSON input" significa que el cuerpo venía completamente vacío, típico de una respuesta 204 o de una petición que falló antes de devolver nada. "Unexpected token }" suele indicar una coma final antes de la llave de cierre, algo que los objetos literales de JavaScript permiten pero JSON prohíbe estrictamente. Y "Unexpected token '" significa que se usaron comillas simples para las cadenas, que de nuevo es JavaScript válido pero JSON inválido.
Cómo encontrarlo en diez segundos
Antes de tocar la lógica de parseo, imprime typeof tuValor justo antes de la llamada a JSON.parse. Si sale "object", borra el JSON.parse — el valor ya está parseado y estabas a punto de desparsearlo. Si sale "string", abre la pestaña Network de las devtools del navegador y mira el cuerpo de la respuesta en crudo, no la vista previa formateada, porque las devtools renderizan encantadas una página de error HTML de forma que parece estructurada. El texto en crudo te dice la verdad de un vistazo.
Cuando tengas el texto real de la respuesta, pégalo en nuestro formateador de JSON — valida la sintaxis y señala el carácter exacto donde se rompe la estructura, mucho más rápido que leer a ojo un payload minificado de una sola línea. Todo funciona en tu navegador, así que es seguro pegar una respuesta real de una API mientras depuras.