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
defaulthandler 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
Built Distribution
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90516c3c8cce6e1eb2af038a0b2c9de9e414a1c6ffefa207c4575b9f08f2c587
|
|
| MD5 |
5e26218c5acf599f914ab69092a62345
|
|
| BLAKE2b-256 |
795e43d459f6ba0c1e2641e945d8d63b7258093935d90b003660eb93f5aaa228
|
Provenance
The following attestation bundles were made for jsonwhy-0.2.0.tar.gz:
Publisher:
publish.yml on Abhay-2004/jsonwhy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonwhy-0.2.0.tar.gz -
Subject digest:
90516c3c8cce6e1eb2af038a0b2c9de9e414a1c6ffefa207c4575b9f08f2c587 - Sigstore transparency entry: 2159192581
- Sigstore integration time:
-
Permalink:
Abhay-2004/jsonwhy@464bb133d33987b11f0b6b923ffda8a68ef411ef -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Abhay-2004
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@464bb133d33987b11f0b6b923ffda8a68ef411ef -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dda5578a6995924caa3398ba050e8d5fbed990b799cb9e8f5b121bf21ac63d36
|
|
| MD5 |
3e3913a07743379c438334a9159d831c
|
|
| BLAKE2b-256 |
681187348d8c05f769045be3d34e70a015082507601e059e3d02174b08f8e96b
|
Provenance
The following attestation bundles were made for jsonwhy-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Abhay-2004/jsonwhy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonwhy-0.2.0-py3-none-any.whl -
Subject digest:
dda5578a6995924caa3398ba050e8d5fbed990b799cb9e8f5b121bf21ac63d36 - Sigstore transparency entry: 2159192614
- Sigstore integration time:
-
Permalink:
Abhay-2004/jsonwhy@464bb133d33987b11f0b6b923ffda8a68ef411ef -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Abhay-2004
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@464bb133d33987b11f0b6b923ffda8a68ef411ef -
Trigger Event:
release
-
Statement type: