One exception is trailing-commas. Another is leading 0 in numbers for example
-02. The former is for practicality. The latter is for compatibility with DynamicJson.
The grammar of JSON is simple, but carelessly implemented parsers don't accept all conformant and not reject non-conformant JSONs. An excellent article of Parsing JSON is a Minefield shows where mines are in implementing JSON parsers.
For example, some parsers reject just scalars such as
null. Some parsers reject arrays of empty arrays such as
[], or numbers whose exponent digit is 0 like
1e0. Many parsers reject objects whose keys are not unique such as
Most parsers accept various non-conformant JSONs. They allow numbers such as
+1, strings containing not escaped control characters or trailing garbage such as
DynaJson had struck many mines at first because of prejudice and carelessness. I finally made it strict as mentioned above. It rejects most non-conformant JSONs to detect breakage.
The left part shows the files of tested JSONs. The center has the results. The right shows the JSONs. Parsers must accept files starting with
y_, should reject with
n_, can take either way about
i_. The upper-left corner shows how the color of each result means.
System.Text.Json introduced since .NET Core 3.0 is the strictest. It accepts all conformant and rejects all non-conformant, but can accept trailing-commas with an option. Only Utf8Json among them can't take trailing-commas.
Each parser has a pattern of accepted non-conformant JSONs. Json.NET takes objects whose keys are not strings. Utf8Json allows trailing garbages. DynamicJson takes objects not enclosed with
}. Jil allows incorrect exponent parts in numbers.
The results colored red at the bottom are of parsing JSONs nested 100,000 times and not closed. Parsers should reject them. But DynamicJson resulted in a timeout after processing 5 sec. Jil and Utf8Json caused stack overflow and crashed.
Json.NET allows unlimited nesting until the upper bound of memory by default. It can reject them with syntax errors. System.Text.Json and DynaJson have configurable maximums of the nesting level. The former is 64, and the latter is 512. So both reject the JSONs because of too deep nesting.