Skip to main content

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 to json.loads.
  • Always re-parseable. result.json is 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

safe_json_repair-0.1.1.tar.gz (32.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (264.9 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (253.3 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl (242.4 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl (251.9 kB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

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

Hashes for safe_json_repair-0.1.1.tar.gz
Algorithm Hash digest
SHA256 b4ff245c0041af020e304ea390a4b8beb44e6dcd92cc95e242c74f47ca89af34
MD5 050a35c2a4c3f10772705bc33e8d602e
BLAKE2b-256 ff2f6ab03be9b1001cb7919177ead97fe630f57012cc59a3443278151efd4911

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

File hashes

Hashes for safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 40192a735f0493d83be9ea441a5a1b59e90543177acfc1a52819646bf1b43122
MD5 7c0dc96793b593a0f92e6b9a836c8953
BLAKE2b-256 1946f247c42e9aa8502465285a7135900d21d92a335bc3c7be34e0eb17350f24

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for safe_json_repair-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5e6af9b949ce281449f440ae0cc2fe22921ca93f976c5b8701e6dd63043c4f68
MD5 2d959ccef09f3aa1f77a7cc9203a2598
BLAKE2b-256 e0321927636a630bf9fd87c2e32570bf8ccd8e22ad8581be9c039c76b380b751

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for safe_json_repair-0.1.1-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a3527692d5e9da0c2e75282fe2c0a9c4d8a74896ac8b1a51d77622a6457ae81a
MD5 1982432313c85d587650124ca528639f
BLAKE2b-256 4ebf0340854b1499ad6a4c45c58799e225bfeb4f6f6fed37bda0cab759872323

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for safe_json_repair-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 3e8675f22b2fdd9498c05964370c8aaf7ffae116d093d0f03db4bee4dd44202f
MD5 5e8be2e68179367605eb6b417e1076fc
BLAKE2b-256 11963205f0597916264ca1ba2c0464741bc1f35a42f076c4b9f142ed9a919ebc

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page