Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

¿JSONDecodeError: Extra data en Python? Identifica el encuadre antes de analizar

El primer valor JSON puede ser válido y aun así quedar contenido. Conserva los bytes, distingue un documento, JSON Lines o valores concatenados y valida toda la entrada.

Ilustración editorial original que compara un documento JSON, JSON Lines y valores JSON concatenados.
Ilustración editorial original que compara un documento JSON, JSON Lines y valores JSON concatenados. Watch at Ease

Extra data significa que Python terminó de decodificar un valor JSON completo y encontró después algo que no era espacio en blanco. Por sí solo no demuestra que el archivo sea JSON Lines ni que la línea 2 sea un registro seguro. Conserva los bytes originales y confirma el contrato de encuadre del productor antes de elegir un analizador o reescribir.

Conserva la evidencia y clasifica el sufijo

Copia o calcula el hash del archivo antes de experimentar. Anota la codificación, la presencia de BOM, el mensaje, pos, lineno, colno y una vista escapada alrededor del fallo. No borres espacios, no reemplaces cada }{ ni envuelvas texto bruto entre corchetes: esos cambios pueden alterar cadenas, ocultar corrupción o inventar separadores.

Usa JSONDecoder.raw_decode sobre el texto decodificado para saber dónde termina el primer valor y examina solo lo restante. Si queda únicamente espacio, era un documento. Si empieza otro valor, confirma si el productor promete un valor completo por línea, valores adyacentes o bytes añadidos por error. El contrato decide el analizador, no la línea del error.

Elige el analizador según el contrato de registros

Para un documento JSON usa json.load o json.loads como comprobación estricta. Un objeto, array, cadena, número, booleano o null superior cuenta como un valor y el material final sin explicación debe seguir siendo un error. Si controlas una colección, un único array superior es la representación JSON más portátil.

Para JSON Lines, abre como UTF-8 y decodifica cada línea física no vacía solo si cada línea contiene un valor JSON completo. Se permiten objetos, arrays y escalares, pero no líneas vacías. Un objeto con formato en varias líneas no es un registro JSON Lines y fallará al analizarlo línea por línea.

Consume valores adyacentes sin adivinar delimitadores

Si el productor realmente concatena valores JSON sin garantía de línea, un bucle raw_decode que salta espacios puede devolver cada valor y su índice final. Valida el tipo o esquema de cada registro, conserva su número e índice inicial cuando falle y exige que el índice final alcance EOF tras los espacios.

raw_decode recibe una cadena que empieza con un documento JSON; no se convierte automáticamente en un lector acotado de flujo. Un archivo grande necesita un diseño de búfer o un analizador de flujo revisado. No reemplaces globalmente }{ por },{, porque esos caracteres pueden aparecer dentro de cadenas y los límites dañados deben rechazarse.

Convierte posiciones de caracteres a bytes y valida antes de transformar

Python define JSONDecodeError.pos como el índice inicial dentro de doc; lineno y colno se calculan sobre la cadena decodificada. En nuestra prueba con Python 3.12.14, {"é":1}{"b":2} falló en pos 7, pero había ocho bytes UTF-8 antes del segundo valor. Usa len(text[:pos].encode("utf-8")); nunca hagas seek binario directo a pos si antes puede haber texto no ASCII.

En la misma prueba, JSON Lines produjo Extra data en línea 2 columna 1, valores compactos en línea 1 columna 8 y dos objetos con formato en línea 4 columna 1. raw_decode consumió las tres secuencias; el modo por líneas solo funcionó para JSON Lines. Convierte únicamente después de validar sintaxis y reglas de cada valor, consumir todo el sufijo y cuadrar el número de registros; serializa a un archivo temporal nuevo y conserva el original.

Ilustración editorial original que muestra la diferencia entre posición de carácter y desplazamiento UTF-8.
Ilustración editorial original que muestra la diferencia entre posición de carácter y desplazamiento UTF-8. Watch at Ease