← Todos los artículos

Unexpected Token o en JSON en la posición 1: causas y arreglo

Esa «o» minúscula es el segundo carácter de «[object Object]». Pasaste un objeto JavaScript a JSON.parse() en vez de una cadena. Aquí cada variante de este error y el arreglo de una línea para cada una.

SyntaxError: Unexpected token o in JSON at position 1 — esa o minúscula es el segundo carácter de [object Object]. Significa que pasaste un objeto JavaScript directamente a JSON.parse() en lugar de una cadena JSON. Este artículo explica cada variante del error y cómo arreglar cada una en menos de un minuto.

Por qué el error dice "token o"

Cuando pasas un valor no-cadena a JSON.parse(), JavaScript primero lo convierte forzosamente a cadena. Un objeto plano se convierte en "[object Object]". El parser ve [ en la posición 0 (válido — inicia un array), luego o en la posición 1 (inválido — no es un elemento de array válido). De ahí: Unexpected token o at position 1.

JSON.parse({})
// Igual a: JSON.parse("[object Object]")
// SyntaxError: Unexpected token o in JSON at position 1

La causa más común: no esperar response.json()

Esta es la fuente número uno de este error en bases de código reales. Un objeto Response de fetch() no es una cadena: es un envoltorio de ReadableStream. Pasarlo a JSON.parse() lo convierte forzosamente a "[object Response]".

// ❌ Incorrecto — response es un objeto Response, no una cadena
const response = await fetch('/api/user');
const data = JSON.parse(response);
// SyntaxError: Unexpected token o in JSON at position 1

// ✓ Correcto — deja que el navegador parsee el stream como JSON
const data = await response.json();

De igual modo, si llamas a response.text() sin await, obtienes un objeto Promise (que se convierte forzosamente a "[object Promise]").

// ❌ Falta await — text es una Promise, no una cadena
const text = response.text();
const data = JSON.parse(text);
// SyntaxError: Unexpected token o in JSON at position 1

// ✓ Correcto
const text = await response.text();
const data = JSON.parse(text);

Otros objetos que disparan este error

Lo que pasasteA lo que JS lo convierteToken del error
{} o cualquier objeto plano"[object Object]"token o en la posición 1
undefined"undefined"token u en la posición 0
true / false"true" / "false" — ¡en realidad es JSON válido!sin error
Un objeto Response"[object Response]"token o en la posición 1
Una Promise"[object Promise]"token o en la posición 1
null"null" — JSON válidosin error (devuelve null)

Causa: pasar un objeto en vez de serializarlo

Un error relacionado: intentar "parsear" un objeto JavaScript que ya tienes en memoria. JSON.parse() recibe una cadena; si ya tienes un objeto, no necesitas parsearlo.

const config = { host: 'localhost', port: 3000 };

// ❌ Sin sentido — config ya es un objeto
const parsed = JSON.parse(config);

// ✓ Si quieres una copia profunda, usa structuredClone o stringify + parse
const clone = JSON.parse(JSON.stringify(config));

// ✓ Si quieres enviarlo, usa JSON.stringify
const body = JSON.stringify(config);

Causa: Python u otro backend devuelve un Content-Type incorrecto

A veces el servidor devuelve un mensaje de error en texto plano (como "ok" o "not found") con estado 200 y sin cabecera Content-Type. El frontend asume JSON, llama a response.json() y obtiene un error de token inesperado porque el cuerpo no es JSON válido.

// El servidor envía la cadena literal: ok
// El navegador intenta parsearla como JSON:
JSON.parse("ok")
// SyntaxError: Unexpected token o in JSON at position 0

Solución: Verifica siempre response.ok y response.headers.get('Content-Type') antes de llamar a response.json():

const response = await fetch('/api/action');
if (!response.ok) {
  const text = await response.text();   // seguro — quizá no sea JSON
  throw new Error(`HTTP ${response.status}: ${text}`);
}
const data = await response.json();

Variantes menos comunes de [object X]

Cualquier valor cuyo toString() devuelva una cadena que empiece con [object dispara el mismo error en la posición 1. Más allá de [object Object], los que realmente aparecen en código real:

  • [object Module] — pasar el resultado de un import dinámico: const mod = await import('./data.json', { with: { type: 'json' } }); quieres mod.default, no mod.
  • [object AsyncFunction] — pasar la referencia de una función asíncrona en lugar de llamarla: serializa fn() (el valor resuelto de la promesa), no fn.
  • [object HTMLDocument] — pasar document por error (p. ej., desde un snippet del depurador rezagado).
  • [object FormData] — usar fetch(url, { body: formData }) está bien, pero JSON.parse(formData) no — conviértelo primero con Object.fromEntries(formData).

Lista rápida de correcciones

  • ¿fetch + JSON.parse? Reemplázalo por await response.json().
  • ¿Falta un await en alguna parte de la cadena? Cada llamada async previa al parseo debe estar await-eada.
  • ¿Ya tienes un objeto? No necesitas parsearlo — úsalo directamente o clónalo con structuredClone().
  • ¿El servidor devuelve no-JSON en error? Léelo con response.text(), no con response.json(), cuando la respuesta podría no ser JSON.

Preguntas frecuentes

¿Qué significa "Unexpected token o in JSON at position 1"?

Pasaste un objeto JavaScript a JSON.parse(). JavaScript convierte el objeto forzosamente a la cadena "[object Object]"; el parser acepta [ en la posición 0 pero rechaza la o en la posición 1.

¿Cómo lo arreglo con fetch?

No llames a JSON.parse(response). Usa await response.json(), que lee el stream de respuesta y lo parsea por ti. Asegúrate de await-ear cada paso de la cadena.

¿Necesito JSON.parse si ya tengo un objeto?

No. JSON.parse() solo convierte una cadena JSON en un valor. Si ya tienes un objeto, úsalo directamente, o hazle copia profunda con structuredClone() en vez de JSON.parse(JSON.stringify(obj)).

¿"Unexpected token o" es lo mismo que "[object Object] is not valid JSON"?

Comparten la misma causa raíz: un objeto convertido a cadena antes de parsearlo. Las versiones nuevas de V8 imprimen [object Object] is not valid JSON; las antiguas imprimen Unexpected token o. Consulta Arreglar "[object Object] is not valid JSON" para el desglose completo.

Inspecciona la respuesta cruda

Si no sabes qué está devolviendo tu API, pega el cuerpo crudo en JSON Fix para validarlo. Si no es JSON válido, el validador te dirá exactamente qué está mal.