safe-json-repair (Python)
Repair broken JSON from LLMs — never throws, never silently drops a field. One synchronous call, native (PyO3 over the Rust core — no wasm).
pip install safe-json-repair # or: uv add safe-json-repair
from safe_json_repair import repair_json
r = repair_json('{"a":1}, "b":2}') # a stray "}" closed the root early
r.ok # True
r.value # {'a': 1, 'b': 2} ← "b" is NOT lost
r.json # '{"a":1,"b":2}'
r.strategy # 'tolerant'
What problem this solves
LLMs in tool-calling / structured-output mode (DeepSeek, OpenAI, …) routinely return JSON with a stray closing delimiter that closes the parent or root object too early, orphaning every field that comes after it. On that exact shape the popular repair libraries either throw or silently drop the orphaned fields — and a silently dropped field is the dangerous failure: your tool call loses data and you never find out. This library keeps it.
Usage
The full result
from safe_json_repair import repair_json
r = repair_json(maybe_broken_json)
if r.ok:
do_something(r.value) # recovered value (already a dict/list/…)
else:
# Only for unrepairable garbage. r.value is the fallback (None by default).
log.warning("could not repair JSON: strategy=%s", r.strategy)
Convenience wrappers
from safe_json_repair import parse_json_safe, repair_json_string
# Just the value — or None if nothing could be recovered.
args = parse_json_safe(broken_tool_args)
# Just the repaired JSON string — or None.
text = repair_json_string(broken_tool_args)
Real-world: guarding an LLM tool call
from safe_json_repair import parse_json_safe
def read_tool_args(raw: str) -> dict:
# Usually valid JSON (fast path, zero rewrite). When it isn't, we recover
# instead of crashing the turn — and keep every field, so the downstream
# tool gets complete arguments.
args = parse_json_safe(raw, fallback="empty-object")
if args is None:
raise ValueError("tool args unrecoverable")
return args
repair_json is synchronous and never raises on input shape — any
input, including pure garbage, returns a deterministic RepairResult. (Only an
invalid option, such as an unknown fallback, raises ValueError.)
API
def repair_json(input: str, *, max_len=None, fallback=None,
strip_code_fences=None, unwrap_double_encoded=None) -> RepairResult: ...
def parse_json_safe(input: str, **options) -> Any | None: ...
def repair_json_string(input: str, **options) -> str | None: ...
Options (each None ⇒ the core default):
| Option | Default | Meaning |
|---|---|---|
max_len |
5_000_000 |
inputs longer than this (bytes) skip to the fallback |
fallback |
"null" |
what to return when nothing parses: "null" or "empty-object" |
strip_code_fences |
True |
strip ```json … ``` wrappers |
unwrap_double_encoded |
True |
unwrap a JSON string that itself encodes an object/array |
RepairResult (immutable):
| Attribute | Type | Meaning |
|---|---|---|
ok |
bool |
False only when it fell through to the fallback |
value |
Any |
the recovered value (the fallback value when not ok) |
json |
str |
canonical JSON serialization of value (always re-parseable) |
changed |
bool |
was the original input altered to produce this? |
strategy |
str |
which rung of the ladder fired (see below) |
strategy is one of: 'parse', 'strip-fences', 'strip-controls',
'strip-trailing-commas', 'unwrap-double', 'tolerant', 'fallback'.
Guarantees
- Never throws on input. Every input returns a
RepairResult. Garbage →'fallback'. - Never silently drops data. Siblings orphaned by a premature close are kept.
- Never rewrites valid JSON. Valid input takes the fast path:
strategy='parse',changed=False, value identical tojson.loads. - Always re-parseable.
result.jsonis always valid JSON.
How it's built
This package is a thin PyO3 wrapper over the same Rust
core published as the safe-json-repair crate
and the npm package — there is
no second reimplementation to drift out of sync. All three bindings run the same
golden corpus (corpus/cases.json). Native code, no wasm.
Building from source
cd bindings/python
uv venv && uv pip install maturin pytest
maturin develop # compile + install into the venv
pytest # runs the shared golden corpus + API tests
License
MIT © LcpMarvel
Metadata
Release files for safe-json-repair 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| safe_json_repair-0.1.1.tar.gz | 32.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.8 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.8 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl | CPython 3.8 | abi3 | macOS 11.0+ ARM64 | Details |
| safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl | CPython 3.8 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 1.0 MB
Release files / safe_json_repair-0.1.1.tar.gz
| Download URL | safe_json_repair-0.1.1.tar.gz |
|---|---|
| Size | 32.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4ff245c0041af020e304ea390a4b8beb44e6dcd92cc95e242c74f47ca89af34
|
|
BLAKE2b-256 checksum How to use checksums |
ff2f6ab03be9b1001cb7919177ead97fe630f57012cc59a3443278151efd4911
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 264.9 kB |
| Tags | CPython 3.8 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
40192a735f0493d83be9ea441a5a1b59e90543177acfc1a52819646bf1b43122
|
|
BLAKE2b-256 checksum How to use checksums |
1946f247c42e9aa8502465285a7135900d21d92a335bc3c7be34e0eb17350f24
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 253.3 kB |
| Tags | CPython 3.8 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
5e6af9b949ce281449f440ae0cc2fe22921ca93f976c5b8701e6dd63043c4f68
|
|
BLAKE2b-256 checksum How to use checksums |
e0321927636a630bf9fd87c2e32570bf8ccd8e22ad8581be9c039c76b380b751
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl
| Download URL | safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 242.4 kB |
| Tags | CPython 3.8 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a3527692d5e9da0c2e75282fe2c0a9c4d8a74896ac8b1a51d77622a6457ae81a
|
|
BLAKE2b-256 checksum How to use checksums |
4ebf0340854b1499ad6a4c45c58799e225bfeb4f6f6fed37bda0cab759872323
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency logRelease files / safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl
| Download URL | safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 251.9 kB |
| Tags | CPython 3.8 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
3e8675f22b2fdd9498c05964370c8aaf7ffae116d093d0f03db4bee4dd44202f
|
|
BLAKE2b-256 checksum How to use checksums |
11963205f0597916264ca1ba2c0464741bc1f35a42f076c4b9f142ed9a919ebc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.
Transparency log