One JSON value per line
JSON Lines (also called NDJSON or LDJSON) stores one complete JSON value on each line, separated by newlines. It is the format of OpenAI and Vertex AI fine-tuning datasets, BigQuery and Elasticsearch bulk imports, many structured loggers and streaming APIs. Because each line is parsed on its own, one malformed record can break an import at row 31,207 while every other row is fine. That is exactly the case this validator is built for.
For a file to be valid:
- every non-empty line is a complete JSON value, usually an object;
- each value follows strict JSON rules: double quotes, no trailing commas, no comments, no
NaN; - a record must not be spread over several lines.
Blank lines are tolerated and ignored, which matches what most readers do. Records do not all have to be objects or share the same keys; a line holding an array or a plain string is valid JSON Lines, even if your importer expects something narrower.
Errors that name the record
Every message starts with the record it concerns, as in Record on line 2: Trailing comma before '}', followed by a hint like “JSON does not allow a comma after the last property”. The line is highlighted in the editor, and the rest of the file stays readable. In the output pane, the result from the last clean pass is kept on screen in a faded state while you repair the record, so you can compare before and after.
A pretty-printed record that spans several lines is a special case. Strictly it breaks the format, but the intent is obvious, so the validator joins it into one line and adds an informational note instead of an error. If your producer emits multi-line records, fix it at the source: most JSON Lines readers split on newlines and will fail.
Common causes of bad records
Exports written by string concatenation produce most broken rows: a trailing comma left by a loop, single quotes from a Python str(dict), or an unescaped newline inside a message field. Truncated last lines are another classic, when a log file is copied while it is still being written. And sometimes the whole file is a JSON array rather than JSON Lines; an array on a single line is technically one valid record, so use JSON Lines to JSON or JSON to JSON Lines to switch between the two shapes deliberately.
The check is syntax only. It does not verify that every record has the same keys, that a messages array follows a fine-tuning schema, or that timestamps are sorted; the Table view helps you eyeball consistency across records. Files are parsed in your browser, so logs with user IDs or prompts with private data stay on your machine.
Examples
Trailing comma in one event
Invalid: record 2 has a comma before its closing brace, and the message names line 2 directly.
{"event":"signup","user":"usr_42","ts":"2026-09-14T08:21:05Z"}
{"event":"purchase","user":"usr_42","total":129.9,}
{"event":"logout","user":"usr_42","ts":"2026-09-14T08:40:12Z"}Line 2, column 50: Record on line 2: Trailing comma before '}'Python-style quotes in a dataset row
Invalid: the second record uses single quotes, which JSON Lines inherits as an error from JSON.
{"prompt":"Summarise order ord_8f2k1","completion":"Shipped on 14 Sep"}
{'prompt':'Summarise order ord_9a1x2','completion':'Awaiting payment'}Line 2, column 2: Record on line 2: Object keys must use double quotes, not single quotesA record split across lines
Accepted with a note: the first record is joined into one line because JSON Lines requires one record per line.
{"level":"info","msg":"server started",
"port":8080}
{"level":"warn","msg":"slow query","ms":812}{"level":"info","msg":"server started","port":8080}
{"level":"warn","msg":"slow query","ms":812}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Record on line 2: Trailing comma before '}'Explained | The writer appended a comma after the last property of that record. | Remove the comma, or use Fix it on that record. |
Record on line 2: Strings must use double quotes, not single quotesExplained | The record was produced with str() or repr() in Python rather than json.dumps(). | Regenerate the file with json.dumps(), or replace the quotes in that record. |
Record on line 2: Unexpected word 'not' — strings must be in double quotes | A plain text line, such as a log banner or a stack trace line, is mixed into the file. | Delete non-JSON lines or filter them out before importing. |
The record on line 1 spans 2 lines; JSON Lines needs one record per line, so it was joined | A record was pretty-printed over several lines. | Nothing to do here, but configure the producer to write compact records. |
Frequently asked questions
Is NDJSON the same as JSON Lines?
For practical purposes, yes. Both mean one JSON value per line separated by newlines; the names come from two separate specifications that describe the same format.
Are empty lines allowed?
They are skipped. Most readers do the same, though a strict producer should not write them.
Can I validate an OpenAI fine-tuning file here?
You can check that every line is valid JSON, which is the most common reason uploads fail. The validator does not check the messages schema itself.
How large a file can I check?
Large exports are fine because each line is parsed independently. On very big files, use Ctrl/Cmd+Enter to validate on demand instead of while typing.