JsonRepair 0.2.0
dotnet add package JsonRepair --version 0.2.0
NuGet\Install-Package JsonRepair -Version 0.2.0
<PackageReference Include="JsonRepair" Version="0.2.0" />
<PackageVersion Include="JsonRepair" Version="0.2.0" />
<PackageReference Include="JsonRepair" />
paket add JsonRepair --version 0.2.0
#r "nuget: JsonRepair, 0.2.0"
#:package JsonRepair@0.2.0
#addin nuget:?package=JsonRepair&version=0.2.0
#tool nuget:?package=JsonRepair&version=0.2.0
๐ฅฉ JsonRepair.NET โ Powered by Bifteki Crew ๐ฅ
Flame-grilling malformed, broken LLM JSON into standard valid JSON at lightning speed.
Status: 0.x โ the API may change between minor versions based on real-world feedback. Pin an exact version in production, and please report repair failures with a sample input.
JsonRepair.NET is an ultra-fast, zero-allocation C# 13 / .NET 10 library crafted by the Bifteki Crew. It repairs raw, truncated, or non-standard JSON generated by Large Language Models (LLMs) and legacy APIs into strictly conforming JSON parseable by System.Text.Json.
๐ฅฉ Why Bifteki JsonRepair.NET?
LLMs (OpenAI, DeepSeek, Anthropic, Ollama) frequently produce "burnt" or broken JSON outputs that crash standard parsers with JsonException:
- โ Markdown Fences:
```json { ... } ``` - โ Single Quotes:
{'user': 'Bifteki Chef'} - โ Unquoted Keys:
{name: "Alice"} - โ Python / JS Literals:
Noneโnull,Trueโtrue,undefinedโnull - โ Trailing Commas:
[1, 2, 3,] - โ Unclosed Truncated JSON:
{"items": [1, 2
JsonRepair.NET uses a single-pass ref struct state machine to repair all these syntax errors. The UTF-8 ReadOnlySpan<byte> engine writes into an IBufferWriter<byte> you own with zero heap allocations, at any payload size; the string API uses pooled buffers and allocates in proportion to the input.
๐ Quick Start
1. Installation
dotnet add package JsonRepair
2. Basic Usage
using JsonRepair;
string malformedLlmJson = """
```json
{
crew: 'Bifteki Team',
flame_grilled: True,
secret_ingredient: None,
items: ['Patty', 'Garlic',],
```
""";
// Repair into valid standard JSON
string repaired = JsonRepairEngine.Repair(malformedLlmJson);
Console.WriteLine(repaired);
// Output: {"crew":"Bifteki Team","flame_grilled":true,"secret_ingredient":null,"items":["Patty","Garlic"]}
// Repair either returns valid JSON or throws โ it never hands back something that will not parse.
// TryRepair gives you the same guarantee without the exception:
if (JsonRepairEngine.TryRepair(malformedLlmJson, out string? result))
{
Console.WriteLine(result);
}
// Exception-free Direct Parsing into JsonDocument
if (JsonRepairEngine.TryParse(malformedLlmJson, out JsonDocument? doc))
{
using (doc)
{
Console.WriteLine($"Crew: {doc.RootElement.GetProperty("crew").GetString()}");
}
}
3. UTF-8 Streaming (ReadOnlySpan<byte> / Stream)
using System.Buffers;
using JsonRepair;
// Direct zero-string-allocation UTF-8 byte span repair
byte[] utf8Input = "{item: 'Bifteki', price: 14.99}"u8.ToArray();
var writer = new ArrayBufferWriter<byte>();
JsonRepairEngine.Repair(utf8Input.AsSpan(), writer);
๐ก๏ธ The Repair Contract
Repair has one guarantee: the string it returns parses, or it throws. It never returns
best-effort text that fails later inside your deserializer.
| Outcome | Repair |
TryRepair |
|---|---|---|
| Input repaired | returns valid JSON | returns true |
| Input unrepairable | throws JsonRepairException |
returns false, writes nothing |
JsonRepairException derives from JsonException, so existing catch (JsonException) clauses
keep working. Its message names the reason; the originating exception is kept as InnerException.
try
{
string repaired = JsonRepairEngine.Repair("{a: hello}");
}
catch (JsonRepairException ex)
{
// "Unable to repair the input into valid JSON: 'h' is an invalid start of a value."
Console.WriteLine(ex.Message);
}
Note: error positions are not yet reported against your input. The engine repairs optimistically and validates afterwards, so the only offsets available describe the repaired output โ quoting them would point at the wrong place. Input-relative positions arrive in 0.3.0 with the grammar-based rework.
โก Performance Benchmarks (.NET 10)
Measured with BenchmarkDotNet v0.15.8 and [MemoryDiagnoser] on a GitHub-hosted runner
(AMD EPYC 7763, Ubuntu 24.04, .NET 10.0.11, X64 RyuJIT) โ reproducible by anyone via the
Benchmarks (Manual) workflow. Run-to-run deviation there is under 0.2%.
string API โ Repair(string)
| Payload | Latency | Throughput | Allocated |
|---|---|---|---|
| Small (83 B) | 1.05 ยตs | ~954,000 ops/sec | 896 B |
| Medium (2.9 KB) | 33.4 ยตs | ~29,900 ops/sec | 23.0 KB |
| Large (136 KB) | 1.20 ms | ~830 ops/sec | 1.05 MB |
Small, via TryParse |
1.51 ยตs | ~664,000 ops/sec | 1,400 B |
UTF-8 API โ Repair(ReadOnlySpan<byte>, IBufferWriter<byte>)
Writing into a caller-owned buffer that is reused between calls:
| Payload | Latency | Throughput | Allocated | vs string |
|---|---|---|---|---|
| Small (83 B) | 0.55 ยตs | ~1,816,000 ops/sec | 0 B | 1.9ร faster |
| Medium (2.9 KB) | 19.4 ยตs | ~51,600 ops/sec | 0 B | 1.7ร faster |
| Large (136 KB) | 798 ยตs | ~1,250 ops/sec | 0 B | 1.5ร faster |
Zero bytes, at every payload size. The staging buffer that lets the engine validate output
before any of it reaches your writer is pooled and reused per thread, and its backing array returns
to ArrayPool<byte>.Shared after each call. The string API cannot match this: it must materialise
a result string, so it allocates in proportion to its input.
<details> <summary>Cross-checked on Apple Silicon (M5 Pro, Arm64)</summary>
Allocation figures are identical on both architectures โ they are counted, not timed, so
0 B holds regardless of hardware. Absolute latencies are roughly 1.5โ1.8ร faster than the CI
runner, and the small and medium speedups hold (1.8ร and 1.4ร).
The large payload is the exception: on Arm64 the UTF-8 path measured ~20% slower than the
string API (0.81ร and 0.85ร across two runs), inverting the x64 result. Reproducible on that
machine, not yet explained, and worth profiling โ but it does not appear on x64, so it is an
architecture-specific effect rather than a property of the implementation.
</details>
Reproduce locally with dotnet run --project benchmarks/JsonRepair.Benchmarks -c Release -- --run.
โ ๏ธ Known Limitations (0.x)
The engine repairs the most common LLM/legacy failure modes (see above). Coverage against the upstream josdejong/jsonrepair suite is measured, not estimated: its corpus is ported and runs against both engines on every build, currently at 191/427 (44.7%) with every gap categorised. Unsupported input throws rather than returning something broken.
The largest gaps, by ported corpus cases:
| Not yet repaired | Cases | Planned |
|---|---|---|
Unquoted string values โ {a: hello} |
69 | 0.3.0 |
Number edge cases โ 2., -.5, 001, 2e |
32 | 0.3.0 |
Unescaped-quote heuristics โ {'it's'} |
18 | 0.3.0 |
Ellipsis โ [1, 2, ...] |
18 | 0.3.0 |
HTML entities โ " |
16 | 0.5.0+ |
Smart/typographic quotes โ โโฆโ โโฆโ |
14 | 0.3.0 |
Missing colons โ {a 1} |
10 | 0.3.0 |
| Special unicode whitespace โ NBSP, U+3000 | 9 | 0.3.0 |
Leading commas โ [,1] |
8 | 0.3.0 |
| NDJSON / multiple root values | 7 | 0.4.0 |
Missing values โ {"a":} |
6 | 0.3.0 |
Double-encoded JSON โ {\"a\": \"b\"} |
6 | 0.4.0 |
String concatenation โ "a" + "b" |
5 | 0.4.0 |
JSONP / MongoDB calls โ cb({...}), ISODate(...) |
8 | 0.4.0 |
Full breakdown, including the two known differences between the string and UTF-8 engines, in docs/UPSTREAM.md. Tier schedule in the pre-1.0 roadmap.
๐จ Demo CLI
Try the Bifteki Crew demo CLI:
dotnet run --project src/JsonRepair.Cli
๐ Documentation Package (docs/)
- ๐ arc42-architecture.md: Standardized 12-section arc42 Software Architecture Document.
- ๐ UPSTREAM.md: Upstream version tracking log & synchronization protocol.
- ๐ 01-candidate-assessment.md: Candidate discovery & scanning report.
- ๐ 02-vision-and-architecture.md: Vision & span state machine design.
- ๐ 03-tdd-roadmap.md: TDD test matrix (20+ failure modes).
- ๐ 04-implementation-roadmap.md: Phased delivery roadmap.
- ๐ CHANGELOG.md: Release notes & migration guide between minors.
- ๐ 05-pre-1.0-roadmap.md: Pre-1.0 release tiers (0.1.0 โ 1.0.0), critical-findings gate & hardening plan.
๐ค Attribution & Open Source Credits
JsonRepair.NET is an independent, native .NET 10 implementation inspired by the algorithms and test cases of the following outstanding open-source projects:
- josdejong/jsonrepair (JavaScript / TypeScript, ISC License) by Jos de Jong.
- mangiucugna/json_repair (Python, MIT License) by Mangiucugna.
We express our gratitude to the original authors for their ground-breaking work in JSON repair algorithms. See docs/UPSTREAM.md for sync tracking.
๐ License
Licensed under the MIT License. Craft & Flame-Grilled by the Bifteki Crew ๐ฅฉ๐ฅ
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.