Herramientas para desarrolladores

Errores de JSON: cómo encontrar y corregir un JSON no válido

Comas al final, comillas simples, comentarios, un BOM invisible: pasamos 26 fragmentos de JSON con errores por Chrome, Python y PHP y anotamos qué dice cada uno. Así se lee el mensaje y se corrige la causa real.

Por Publicado el 9 min de lectura

JSON es un formato estricto: basta una coma en el sitio equivocado para que se rechace el archivo entero. Y los mensajes de error no ayudan mucho. Chrome dice una cosa, Python otra y PHP a menudo solo dice «Syntax error». Para saber qué significa de verdad cada mensaje, escribimos 26 fragmentos cortos con los errores más habituales y los procesamos con Chrome 141, Node.js 22 (los dos usan el motor V8, igual que Microsoft Edge), Python 3.13 y PHP 8.3. Puedes pegar tu propio JSON en nuestro formateador de JSON: marca la línea y la columna del primer error y te dice en español la causa probable.

Cómo es un JSON válido

JSON está definido en dos documentos que coinciden entre sí: el RFC 8259 del IETF y ECMA-404. Las reglas caben en una pantalla:

  • Un texto JSON es exactamente un valor: un objeto {…}, un array […], un texto (string), un número, true, false o null.
  • Los textos y los nombres de las propiedades van entre comillas dobles rectas ". No se admiten comillas simples ni tipográficas.
  • Los elementos se separan con comas, pero después del último no va coma.
  • No hay comentarios.
  • Los números son decimales con punto: sin ceros a la izquierda (007), sin coma decimal, sin hexadecimal (0xFF), sin NaN ni Infinity.
  • Dentro de los textos hay que escapar las comillas dobles, las barras invertidas y los caracteres de control como saltos de línea y tabuladores: \", \\, \n, \t.
  • Los espacios, tabuladores y saltos de línea entre elementos se admiten en cualquier sitio.

Muchas cosas que parecen JSON no lo son: un objeto literal de JavaScript, un diccionario de Python mostrado con print(), un archivo de configuración con comentarios. Se parecen lo bastante para engañar a la vista y se alejan lo bastante para fallar en cualquier parser.

El mismo error, tres mensajes distintos

Esto es lo que respondieron los tres parsers ante los errores más habituales. Chrome y Node.js dieron mensajes idénticos en todos los casos.

Chrome 141.0.7390, Node.js 22.22, Python 3.13.16 (json.loads), PHP 8.3.6 (json_decode con json_last_error_msg). Python indica línea, columna y carácter en todos los errores; PHP no da ninguna posición.
ErrorChrome / Node.jsPython 3.13PHP 8.3
Coma antes de }: {"age": 31,}Expected double-quoted property name in JSON at position 11 (line 1 column 12)Illegal trailing comma before end of object: line 1 column 11 (char 10)Syntax error
Coma antes de ]: [1, 2, 3,]Unexpected token ']', "[1, 2, 3,]" is not valid JSONIllegal trailing comma before end of arraySyntax error
Comillas simples: {'name': 'Anna'}Expected property name or '}' in JSON at position 1Expecting property name enclosed in double quotesSyntax error
Falta una coma entre dos propiedadesExpected ',' or '}' after property value in JSONExpecting ',' delimiterSyntax error
Un // comentario en el archivoExpected property name or '}' in JSONExpecting property name enclosed in double quotesSyntax error
NaN como valorUnexpected token 'N', … is not valid JSONaceptado sin errorSyntax error
Salto de línea dentro de un textoBad control character in string literal in JSONInvalid control character atControl character error, possibly incorrectly encoded
Ruta de Windows "C:\Users\anna"Bad escaped character in JSONInvalid \escapeSyntax error
Dos objetos seguidosUnexpected non-whitespace character after JSONExtra dataSyntax error
Entrada vacíaUnexpected end of JSON inputExpecting value: line 1 column 1 (char 0)Syntax error
Una página HTML en lugar de JSONUnexpected token '<', "<!DOCTYPE "... is not valid JSONExpecting value: line 1 column 1 (char 0)Syntax error

Llaman la atención dos cosas. Python es el que más ayuda: nombra de forma explícita la coma sobrante y la marca de orden de bytes. PHP dice «Syntax error» casi siempre, así que el sitio lo tienes que buscar tú. Y Python aceptó NaN, que no es JSON válido. Volvemos a ello más abajo.

Cómo leer un mensaje de error

Cuando un mensaje incluye una posición, cuenta los caracteres desde cero: «position 11» es el carácter número 12, por eso Chrome añade «line 1 column 12». Python también cuenta líneas y columnas desde uno, pero señala la propia coma (columna 11). La posición marca el punto en el que el parser se rindió, que a menudo está un poco después del error real:

  • Una coma antes de un cierre se indica en Chrome en la llave o el corchete, porque el parser solo nota el problema cuando espera otra propiedad y encuentra }.
  • Una coma que falta se indica al principio del siguiente elemento, no al final del anterior.
  • Un cierre que falta se indica al final del todo, por muy arriba que falte.

Un detalle en textos con emojis: JavaScript cuenta un emoji como dos caracteres, así que después de un emoji la columna de Chrome sale una de más. Python y nuestro formateador lo cuentan como uno.

Las versiones antiguas de los navegadores formulan los mismos errores de otra manera. El clásico es «Unexpected token < in JSON at position 0», y significa lo mismo que la fila de HTML de la tabla: el texto empieza por <.

Las causas más frecuentes y cómo resolverlas

Coma después del último elemento

JavaScript permite una coma tras el último elemento de un objeto o un array; JSON no. Suele aparecer al borrar o reordenar líneas a mano. Quita la coma que hay antes de } o ].

Comillas simples y tipográficas

JSON solo acepta la comilla doble recta ". Las comillas tipográficas (“ ” o « ») se cuelan cuando el JSON pasa por un procesador de textos, una app de mensajería o un programa de correo que «embellece» las comillas. Pega primero ese texto en un editor de texto plano o sustituye ahí las comillas.

Objetos de JavaScript y diccionarios de Python

Los nombres de propiedad sin comillas ({name: "Anna"}) son JavaScript válido, pero no JSON. En Python, print(datos) o str(datos) producen comillas simples y True, False y None, todo ello inválido. Usa JSON.stringify() en JavaScript y json.dumps() en Python, que siempre escriben JSON de verdad.

Comentarios

El JSON estándar no tiene comentarios. Algunas herramientas usan formatos ampliados que sí los permiten, como el «JSON with Comments» que Visual Studio Code utiliza para su configuración, o tsconfig.json en proyectos de TypeScript. Por eso un archivo funciona en un programa y falla en otro. Quita // … y /* … */ antes de enviar los datos a un parser estándar.

NaN, Infinity y undefined

JSON no tiene forma de escribir «no es un número» ni «infinito». JavaScript lo sabe: JSON.stringify() escribe null en su lugar. Python no: json.dumps(float('nan')) escribe NaN, que Python vuelve a leer sin quejarse pero que todos los navegadores rechazan. Con allow_nan=False en json.dumps() obtienes un error en lugar de JSON no válido. undefined no es un valor JSON; JSON.stringify() simplemente omite esas propiedades.

Ceros a la izquierda y coma decimal

Los códigos postales como 08001 (Barcelona) o los teléfonos que empiezan por 0 no son números en el sentido de JSON. Escríbelos como texto: "cp": "08001". Otra trampa típica en España es la coma decimal: {"precio": 0,5} se lee como el número 0 seguido de una coma, y después el parser espera un nuevo nombre de propiedad. Escribe 0.5. Si exportas desde Excel o una hoja de cálculo con configuración regional española, merece la pena revisarlo.

Saltos de línea y barras invertidas dentro de textos

No se admite un salto de línea o un tabulador real dentro de un texto; escribe \n y \t. La barra invertida inicia una secuencia de escape, así que en una ruta de Windows hay que duplicarla: "C:\\Users\\anna", o usar barras normales, que Windows también entiende en la mayoría de los casos.

HTML donde se esperaba JSON

Si el error apunta al primer carácter y menciona <, el servidor no envió JSON. Normalmente envió una página HTML: una página de error 404 o 500, una página de inicio de sesión o un aviso de mantenimiento. Comprueba el código de estado y la cabecera Content-Type de la respuesta antes de buscar un error de sintaxis.

Caracteres invisibles

Algunos editores y funciones de exportación guardan los archivos como «UTF-8 con BOM»: con una marca de orden de bytes invisible (U+FEFF) al principio. JSON.parse() la rechaza, y el mensaje de Python incluso sugiere la solución: decodificar el archivo con utf-8-sig. Según el RFC 8259, los programas no deben añadir un BOM al JSON que envían. Nuestro formateador lo elimina y te avisa.

Otros caracteres invisibles son igual de fatales fuera de los textos. En nuestras pruebas, Chrome y Python rechazaron un espacio de no separación (U+00A0), que suele colarse al copiar código de una página web o de un documento, y también los caracteres de anchura cero y las marcas de dirección que insertan los editores de árabe o persa. Dentro de los textos se admiten todos. Si el error señala un punto donde no ves nada raro, borra el espacio que hay ahí y vuelve a escribirlo.

Más de un valor

Dos objetos seguidos no son un texto JSON. Los archivos de registro y las exportaciones de datos usan a menudo JSON Lines (también llamado NDJSON), con un objeto por línea. Esos archivos están bien, pero cada línea hay que procesarla por separado.

Válido, pero sorprendente

Hay JSON válido que aun así no hace lo que esperas:

Nombres duplicados: según el RFC 8259, los nombres DEBERÍAN ser únicos; si no, el resultado es imprevisible. Los tres se quedaron con el último valor.
EntradaChrome / Node.jsPython 3.13PHP 8.3
{"a": 1, "a": 2}a vale 2a vale 2a vale 2
{"id": 12345678901234567890}1234567890123456700012345678901234567890 (exacto)1.2345678901234567E+19 (coma flotante)

La segunda fila importa en la práctica. JavaScript y PHP guardan los números como valores de coma flotante de 64 bits, que solo son exactos hasta 9.007.199.254.740.991 (2^53 − 1). El RFC 8259 recomienda no salir de ese rango. Por eso los identificadores grandes, por ejemplo de bases de datos o redes sociales, conviene enviarlos como texto.

En la otra dirección, JSON.stringify() omite sin avisar las propiedades cuyo valor es undefined o una función, convierte NaN e Infinity en null y las fechas en texto. Un BigInt incluso provoca un error («Do not know how to serialize a BigInt»).

Lista de comprobación cuando se rechaza un JSON

  1. Comprueba que de verdad has recibido JSON: código de estado 200 y Content-Type application/json.
  2. Pega el texto en un formateador y mira la línea indicada y el carácter anterior.
  3. Busca a los sospechosos habituales: una coma al final, comillas simples o tipográficas, un comentario, un nombre sin comillas.
  4. Revisa los valores: True/None de Python, NaN, números con ceros a la izquierda o coma decimal.
  5. Revisa los textos: saltos de línea reales, barras invertidas simples en rutas, espacios invisibles.
  6. Corrige el programa que genera el JSON para que el error no vuelva: usa JSON.stringify(), json.dumps() o json_encode() en lugar de montar el JSON a mano.

Formateador y validador JSONFormatea, embellece, minifica y valida JSON online, con la línea y columna exactas de cada error. Tus datos no salen del navegador.Abrir herramienta

Herramientas de esta guía

Preguntas frecuentes

¿Por qué JSON no admite una coma después del último elemento?

La gramática del RFC 8259 y de ECMA-404 simplemente no la contempla, y el formato se mantiene sin cambios a propósito para que todos los parsers lean los mismos datos de la misma manera. Formatos ampliados como JSON5 admiten comas finales y comentarios, pero un parser JSON estándar los rechaza.

¿Puedo poner comentarios en un JSON?

En JSON estándar, no. Algunos programas aceptan comentarios en sus propios archivos de configuración, como los ajustes de Visual Studio Code o el tsconfig.json de TypeScript, pero los datos que envías a una API o lees con JSON.parse() no deben contener ninguno. Si necesitas notas, añádelas como una propiedad normal, por ejemplo "_comentario".

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

El texto empieza por «<», así que casi seguro es HTML, por ejemplo una página de error o de inicio de sesión, y no JSON. Las versiones nuevas de Chrome lo formulan como Unexpected token '<', "<!DOCTYPE "... is not valid JSON. Comprueba la dirección a la que llamas y el código de estado de la respuesta.

¿Por qué Python acepta NaN si los navegadores lo rechazan?

El módulo json de Python lee y escribe por defecto NaN, Infinity y -Infinity con sus nombres de JavaScript, aunque no forman parte del estándar JSON. Con json.dumps(datos, allow_nan=False) te aseguras de generar solo JSON válido.

¿Se sube a algún sitio el JSON que pego en el formateador?

No. Nuestro formateador de JSON funciona por completo en tu navegador. El texto se comprueba y se formatea en tu dispositivo y no se envía a ningún servidor.

¿Por qué mi identificador grande cambia al leerlo?

JavaScript guarda todos los números como valores de coma flotante de 64 bits, que solo son exactos hasta 9.007.199.254.740.991. Los enteros mayores se redondean. Envía esos identificadores como texto, por ejemplo "id": "12345678901234567890".

Fuentes y lecturas recomendadas

  1. RFC 8259 – The JavaScript Object Notation (JSON) Data Interchange Format (www.rfc-editor.org)
  2. ECMA-404 – The JSON data interchange syntax (2nd edition, 2017) (ecma-international.org)
  3. MDN Web Docs: JSON.parse() (developer.mozilla.org)
  4. Python documentation: json – JSON encoder and decoder (docs.python.org)
Todas las guías