Why line-level validation matters
JSONL is one JSON object per line, and a fine-tuning upload rejects the entire file for a single malformed row. The error you get back is often a line number and nothing else, on a file with fifty thousand rows.
Validating locally first turns that into a specific line and a specific parse message, which takes seconds instead of a round trip.
The structural checks
Parsing is necessary and not sufficient. A row that parses perfectly can still be useless for training, and the two most common cases are checked here.
A row with no assistant turn has nothing for the model to learn from — it is input without a target. A row with non-string content usually means a nested object leaked in from a serialisation step and will be rejected or, worse, silently mangled.
Before you upload
Run the deduplicator first. Datasets assembled from support tickets or logs are full of near-identical rows, and duplicates both waste training budget and skew the model towards whatever was repeated.
Then split into training and validation sets with a fixed seed, so the evaluation you run tomorrow is comparable to the one you ran today.