Toolkit Labs

the full leaderboard

Truncated JSON from a stream — 21 parsers

A streaming reply that stopped mid-object is the one failure a dialect parser cannot help with: the text is not loose JSON, it is unfinished JSON, and a parser has to decide what the missing part was. This page is one column of the leaderboard pulled out and read properly — 11 Python and 10 JavaScript parsers on the same 25 truncated cases, one run each, nothing tuned afterwards.

Cases: the truncated category of MALFORMED-300, 25 labelled outputs cut off mid-string, mid-number, mid-array and mid-object. Python measured 2026-08-19T12:31:18Z on Python 3.12.3; JavaScript 2026-08-19T12:33:03Z on node v25.8.2. Corpus sha256 ded36c275f9ff481a9e264f9e900ccbb16da9cf430ff6fe8ffc23b9c02acb88a.

Python

parserrecovered exactlyrefusedreturned a wrong valuesame library, all 300
json-repair 0.63.223 / 2502265 / 300
jsonshim (Toolkit Labs)23 / 2502282 / 300
partial-json-parser 0.2.1.1.post713 / 2512047 / 300
commentjson 0.9.00 / 2525058 / 300
demjson3 3.0.50 / 25250110 / 300
dirtyjson 1.0.80 / 25250123 / 300
hjson 3.1.00 / 2525085 / 300
json.loads (stdlib control)0 / 2525025 / 300
json5 0.15.00 / 25250118 / 300
pyjson5 2.0.10 / 25250118 / 300
simplejson 4.1.10 / 2525029 / 300

JavaScript / TypeScript

parserrecovered exactlyrefusedreturned a wrong valuesame library, all 300
jsonc-parser 3.3.120 / 2541157 / 300
best-effort-json-parser 1.5.114 / 25011160 / 300
partial-json 0.1.713 / 2512074 / 300
untruncate-json 0.0.113 / 2512047 / 300
jsonrepair 3.15.012 / 25112205 / 300
dirty-json 0.9.24 / 25615110 / 300
JSON.parse (stdlib control) v25.8.20 / 2525025 / 300
hjson 3.2.20 / 2525095 / 300
json-loose 1.2.40 / 2525080 / 300
json5 2.2.30 / 25250118 / 300

Three outcomes per case, and they add to 25 for every row: the parser returned the expected value, or it refused, or it returned something else. The last column is the one worth reading twice.

A zero here is not a broken library

8 of the 11 Python parsers and 4 of the 10 JavaScript ones recover none of the 25 cases, and that is the design working as intended. json5, pyjson5, hjson, commentjson and their neighbours are dialect parsers: they read a looser grammar than strict JSON, so comments, trailing commas and unquoted keys are inside their job, and a document nobody closed is not. There is nothing to be lenient about until something finishes the text. Every one of them refuses instead of guessing, which on this category is the safe answer.

The column that costs you

Recovering 25 of 25 is not what separates these libraries; refusing cleanly versus answering wrongly is. Across both languages a parser returned a value that was not the expected one, without refusing, 43 times — 4 in Python and 39 in JavaScript. The widest gap is dirty-json, which returns a wrong value on 15 of 25 truncated cases. A refusal is a branch in your code. A wrong value is a row in your database that looks exactly like data, and a truncated reply is precisely the case where the missing half is the half you needed.

The best Python results on this category are a tie — json-repair and jsonshim (Toolkit Labs), each recovering 23 of 25 with 0 refusals between them. In JavaScript the best is jsonc-parser at 20 of 25, refusing 4 and returning a wrong value on 1.

The tool published here does not win this page on recovery alone and is not presented as if it did — on the 275 recoverable cases of the whole corpus json-repair recovers more than jsonshim does. Read the full grid before choosing anything on one category.

Check it yourself

Every number above is computed from the two published run files and the per-case rows the harnesses wrote; the derived counts on this page are published as one small file, so nothing here rests on this page’s word.

truncated.json — the per-parser counts behind both tables · leaderboard.json · leaderboard_js.json · run_leaderboard.py · run_js.mjs

curl -O https://toolkitlabs.org/malformed300/sample30.jsonl
curl -O https://toolkitlabs.org/malformed300/score.py
python3 score.py --corpus sample30.jsonl --parser yourmodule:recover

The free sample carries 2–3 cases from each of the 12 categories, truncation among them, and is CC0 forever. One broken reply rather than a suite? The in-browser tool runs two of these libraries and the strict parser on your own text, in the page, uploading nothing.

What this page does not tell you

The full corpus

The 30 free cases and the scorer are CC0 forever, bought or not. The remaining 270 cases — all 25 truncated ones among them — with the label rationale for each are the paid product, and they are what let you run this on your own parser at full resolution.

Single developer — €29 · Team / CI licence — €99

Instant download after payment; digital goods, delivered immediately. Payments processed by Stripe. Prices include VAT where applicable.