Repair broken JSON from LLMs — never throws, never silently drops a field. Native (PyO3 over the Rust core).
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file safe_json_repair-0.1.1.tar.gz.
File metadata
- Download URL: safe_json_repair-0.1.1.tar.gz
- Upload date:
- Size: 32.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4ff245c0041af020e304ea390a4b8beb44e6dcd92cc95e242c74f47ca89af34
|
|
| MD5 |
050a35c2a4c3f10772705bc33e8d602e
|
|
| BLAKE2b-256 |
ff2f6ab03be9b1001cb7919177ead97fe630f57012cc59a3443278151efd4911
|
Provenance
The following attestation bundles were made for safe_json_repair-0.1.1.tar.gz:
Publisher:
py-release.yml on LcpMarvel/safe-json-repair
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_json_repair-0.1.1.tar.gz -
Subject digest:
b4ff245c0041af020e304ea390a4b8beb44e6dcd92cc95e242c74f47ca89af34 - Sigstore transparency entry: 1812297206
- Sigstore integration time:
-
Permalink:
LcpMarvel/safe-json-repair@df124e1465594df306e4f185a3ba475cd034855f -
Branch / Tag:
refs/heads/master - Owner: https://github.com/LcpMarvel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-release.yml@df124e1465594df306e4f185a3ba475cd034855f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 264.9 kB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40192a735f0493d83be9ea441a5a1b59e90543177acfc1a52819646bf1b43122
|
|
| MD5 |
7c0dc96793b593a0f92e6b9a836c8953
|
|
| BLAKE2b-256 |
1946f247c42e9aa8502465285a7135900d21d92a335bc3c7be34e0eb17350f24
|
Provenance
The following attestation bundles were made for safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
py-release.yml on LcpMarvel/safe-json-repair
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
40192a735f0493d83be9ea441a5a1b59e90543177acfc1a52819646bf1b43122 - Sigstore transparency entry: 1812200480
- Sigstore integration time:
-
Permalink:
LcpMarvel/safe-json-repair@40643bb41d97cfcb55833b976b30a0862167f704 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/LcpMarvel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-release.yml@40643bb41d97cfcb55833b976b30a0862167f704 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 253.3 kB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e6af9b949ce281449f440ae0cc2fe22921ca93f976c5b8701e6dd63043c4f68
|
|
| MD5 |
2d959ccef09f3aa1f77a7cc9203a2598
|
|
| BLAKE2b-256 |
e0321927636a630bf9fd87c2e32570bf8ccd8e22ad8581be9c039c76b380b751
|
Provenance
The following attestation bundles were made for safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
py-release.yml on LcpMarvel/safe-json-repair
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
5e6af9b949ce281449f440ae0cc2fe22921ca93f976c5b8701e6dd63043c4f68 - Sigstore transparency entry: 1812201094
- Sigstore integration time:
-
Permalink:
LcpMarvel/safe-json-repair@40643bb41d97cfcb55833b976b30a0862167f704 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/LcpMarvel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-release.yml@40643bb41d97cfcb55833b976b30a0862167f704 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 242.4 kB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3527692d5e9da0c2e75282fe2c0a9c4d8a74896ac8b1a51d77622a6457ae81a
|
|
| MD5 |
1982432313c85d587650124ca528639f
|
|
| BLAKE2b-256 |
4ebf0340854b1499ad6a4c45c58799e225bfeb4f6f6fed37bda0cab759872323
|
Provenance
The following attestation bundles were made for safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl:
Publisher:
py-release.yml on LcpMarvel/safe-json-repair
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl -
Subject digest:
a3527692d5e9da0c2e75282fe2c0a9c4d8a74896ac8b1a51d77622a6457ae81a - Sigstore transparency entry: 1812201386
- Sigstore integration time:
-
Permalink:
LcpMarvel/safe-json-repair@40643bb41d97cfcb55833b976b30a0862167f704 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/LcpMarvel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-release.yml@40643bb41d97cfcb55833b976b30a0862167f704 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 251.9 kB
- Tags: CPython 3.8+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e8675f22b2fdd9498c05964370c8aaf7ffae116d093d0f03db4bee4dd44202f
|
|
| MD5 |
5e8be2e68179367605eb6b417e1076fc
|
|
| BLAKE2b-256 |
11963205f0597916264ca1ba2c0464741bc1f35a42f076c4b9f142ed9a919ebc
|
Provenance
The following attestation bundles were made for safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl:
Publisher:
py-release.yml on LcpMarvel/safe-json-repair
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl -
Subject digest:
3e8675f22b2fdd9498c05964370c8aaf7ffae116d093d0f03db4bee4dd44202f - Sigstore transparency entry: 1812200217
- Sigstore integration time:
-
Permalink:
LcpMarvel/safe-json-repair@40643bb41d97cfcb55833b976b30a0862167f704 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/LcpMarvel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-release.yml@40643bb41d97cfcb55833b976b30a0862167f704 -
Trigger Event:
workflow_dispatch
-
Statement type: