jsonlkit.com
JSONL (JSON Lines) utilities, in the browser
Say hi →

JSONL Troubleshooting

Reference · updated 28 July 2026 · overview · spec · format comparison · examples · best practices · FAQ · glossary

Most JSONL failures come from a handful of causes, and the error messages rarely name them. This page maps the message you actually see — Extra data, Unexpected token, Expecting value — onto what is really wrong and what to do about it.

"Extra data" / "Unexpected non-whitespace character after JSON"

What it means: something is parsing your JSONL file as a single JSON document. It read line 1 successfully, then found more content and complained.

Where you see it: Python's json.load(f), JavaScript's JSON.parse(text), jq without -c on multi-value input, any "upload a JSON file" form.

The fix: parse line by line, not all at once. json.loads per line in Python, or convert the file to a JSON array first with JSONL → JSON if the consumer genuinely needs one document. This is not a corrupt file — it is the right file being read the wrong way.

"Expecting value: line 1 column 1"

Almost always a byte-order mark. An invisible U+FEFF sits before your opening brace, and the parser sees an unexpected character at the very first position. Editors do not show it, which is why the error looks impossible.

Confirm it in a shell:

head -c 3 data.jsonl | xxd
# efbbbf  ← that is a UTF-8 BOM

The fix: strip it. Our encoding fixer removes it along with other invisible characters, or in Python open the file with encoding="utf-8-sig", which consumes a BOM if present and is harmless if not.

The other cause of this message is an empty or blank first line — some writers emit a leading newline. Skipping blank lines when you read is good practice regardless.

"Unexpected token" part-way through a line

Four usual suspects, in rough order of frequency:

The fix: the Auto-fixer repairs all four and shows what it changed line by line. Run the encoding fixer first if curly quotes or invisible characters are involved — syntax errors are much easier to read once the invisible characters are gone.

The last line is broken and the rest is fine

The file is truncated. A process was killed mid-write, a disk filled up, a download was interrupted, or a container was stopped while flushing. The last record is a half-written fragment.

This is the failure mode JSONL handles best: every complete line before the break is still perfectly good. Drop the last line and carry on:

# Keep everything except the final line
sed '$d' data.jsonl > fixed.jsonl

Compare against a JSON array, where a truncated file has no closing bracket and is entirely unparseable. That resilience is a large part of why log pipelines use JSONL.

"Token too long" / the reader stops early

A line-length limit. The classic case is Go's bufio.Scanner, which gives up on lines over 64 KB — and if you do not check sc.Err(), it stops silently and your program exits successfully having processed half the file.

Java's BufferedReader, some Node stream configurations, and several log shippers have similar caps. The tell is a record count that is lower than wc -l reports, with no error.

The fix: raise the limit (see JSONL in Go for the exact call), and always check the scanner's error. If records are genuinely enormous, truncate the offending fields or move large blobs out of the record and reference them.

Numbers changed value

Floating-point precision. JavaScript and JSON parsers in many languages decode all numbers as IEEE 754 doubles, which represent integers exactly only up to 253. An id like 9007199254740993 comes back as 9007199254740992. Nothing warns you; the file was fine and the parse silently changed the data.

The fix: keep large identifiers as strings in the JSONL. If you cannot change the producer, parse with something that preserves the literal — json.Number in Go, parse_int=str in Python's json.loads, a BigInt-aware library in JavaScript. Snowflake ids, Twitter ids and some database sequences all exceed the safe range.

Non-English text turned into question marks or �

An encoding mismatch that already happened. The bytes were decoded with the wrong character set — usually Windows-1252 bytes read as UTF-8, or the reverse. Once a character has become (U+FFFD), the original is gone: the replacement character carries no information about what it replaced.

The fix is upstream. Re-export as UTF-8, or if you still have the original bytes, convert them properly: iconv -f windows-1252 -t utf-8 in.jsonl > out.jsonl. Our encoding fixer counts replacement characters so you know to go back rather than trying to patch the symptom.

A separate, benign case: \u00e9 style escapes are valid JSON and parse back to é correctly. Ugly in a diff, harmless in data. In Python they come from ensure_ascii=True, the default.

Records look right but a field is always empty

Three quiet causes, none of which raise an error:

Frequently asked questions

What is the fastest way to find which line is bad?

Paste the file into the JSONL validator — it reports every bad line with position, message and a suggested fix, in one pass, without uploading anything. Shell loops that pipe each line through jq work but are slow.

Can a JSONL file have blank lines?

The format says one JSON value per line, so strictly no. In practice most readers skip them and most writers occasionally emit them. Skip them when reading, and strip them with the encoding fixer if a strict consumer objects.

Does JSONL need a trailing newline at the end?

It should have one. Without it, concatenating two files joins the last record of the first to the first record of the second, and wc -l under-counts. Every tool here writes one.

Why does my file work in Python but not in Node?

Usually a BOM (Python's utf-8-sig handles it, JSON.parse does not) or a large integer (Python keeps arbitrary precision, JavaScript does not). Both are covered above.

Is a 1 GB JSONL file too big?

Not inherently — streaming readers use constant memory. It is too big for anything that loads the whole file, which includes most "paste your JSON here" websites. The tools here stream, so 1 GB works in the browser.

Tools mentioned on this page

— S., [email protected]