Skip to main content

Explain exactly why and where Python objects fail JSON serialization

Project description

jsonwhy

Python's JSON encoder tells you which type failed, but not where that value is inside a large payload. jsonwhy adds the missing path and reports other problems it finds in the same pass.

from datetime import datetime

import jsonwhy

payload = {
    "users": [{"name": "Ada", "joined": datetime(2026, 7, 12)}],
    "tags": {"python", "json"},
}

jsonwhy.dumps(payload)
jsonwhy.JsonWhyError: JSON serialization failed with 2 issues:
1. $.users[0].joined: Object of type datetime is not JSON serializable.
   Fix: Convert it with value.isoformat(); preserve timezone information.
2. $.tags: Object of type set is not JSON serializable.
   Fix: Convert it to a list; sort first if deterministic output matters.

Install

python -m pip install jsonwhy

Python 3.10 or newer is required. The package has no runtime dependencies.

API

dumps() and dump() accept the standard json options. Valid input is passed through to the standard library; diagnosis only runs after serialization fails.

encoded = jsonwhy.dumps({"ok": True}, indent=2)

with open("data.json", "w", encoding="utf-8") as output:
    jsonwhy.dump({"ok": True}, output)

Use explain() when you want structured results without raising an exception:

issues = jsonwhy.explain(payload)

for issue in issues:
    print(issue.path)
    print(issue.json_pointer)
    print(issue.kind)
    print(issue.suggestion)
    print(issue.as_dict())

Each issue includes both a readable JSONPath-like path such as $.users[0].joined and an RFC 6901 json_pointer such as /users/0/joined. A pointer is None when the location contains a Python key that cannot exist in a JSON object.

Two shorter checks are also available:

jsonwhy.check(payload)                 # bool
jsonwhy.assert_serializable(payload)   # raises JsonWhyError

jsonwhy detects unsupported values and keys, circular references, non-finite floats when allow_nan=False, failures in custom default handlers, and overly deep structures.

Custom suggestions

Applications can register advice for their own types:

class CustomerId:
    pass


jsonwhy.register_suggestion(CustomerId, "Convert it with str(value).")

This changes the suggested fix only. jsonwhy does not silently convert the value.

Command line

The CLI checks Python literals, which is useful for values such as sets, bytes, complex numbers, and tuple keys.

jsonwhy "{'payload': b'hello', 'tags': {'a', 'b'}}"
jsonwhy --json "{'payload': b'hello'}"
jsonwhy --path-style pointer "{'payload': b'hello'}"
jsonwhy --max-issues 10 --max-depth 200 "{'payload': b'hello'}"

Exit status 0 means compatible, 1 means issues were found, and 2 means the input or command was invalid.

Notes

  • A failing dump() may have written part of its output before the error.
  • Diagnosis may call a custom default handler or construct a custom encoder again after the original failure. These hooks should be safe to repeat.
  • Diagnostic text can contain representations of application values. Treat it with the same care as logs and tracebacks.
  • Custom repr() implementations can perform work or have side effects before their resulting text is shortened.

Bug reports are welcome on the GitHub issue tracker.

License

MIT

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

jsonwhy-0.2.0.tar.gz (14.4 kB view details)

Uploaded Source

Built Distribution

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

jsonwhy-0.2.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file jsonwhy-0.2.0.tar.gz.

File metadata

  • Download URL: jsonwhy-0.2.0.tar.gz
  • Upload date:
  • Size: 14.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for jsonwhy-0.2.0.tar.gz
Algorithm Hash digest
SHA256 90516c3c8cce6e1eb2af038a0b2c9de9e414a1c6ffefa207c4575b9f08f2c587
MD5 5e26218c5acf599f914ab69092a62345
BLAKE2b-256 795e43d459f6ba0c1e2641e945d8d63b7258093935d90b003660eb93f5aaa228

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonwhy-0.2.0.tar.gz:

Publisher: publish.yml on Abhay-2004/jsonwhy

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

File details

Details for the file jsonwhy-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: jsonwhy-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 13.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for jsonwhy-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dda5578a6995924caa3398ba050e8d5fbed990b799cb9e8f5b121bf21ac63d36
MD5 3e3913a07743379c438334a9159d831c
BLAKE2b-256 681187348d8c05f769045be3d34e70a015082507601e059e3d02174b08f8e96b

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonwhy-0.2.0-py3-none-any.whl:

Publisher: publish.yml on Abhay-2004/jsonwhy

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