pythonjsonformatter

Fix Python JSON serialization errors

JSON has fewer data types than Python. Convert unsupported values deliberately instead of hiding the error.

Why “not JSON serializable” appears

json.dumps() handles dictionaries, lists, strings, numbers, booleans, and None. It raises TypeError for values that JSON cannot represent by itself, such as datetime, Decimal, set, bytes, and custom classes.

Choose a representation first

Python valueCommon JSON representation
datetimeISO-8601 string via value.isoformat()
DecimalString when exact precision matters
setList, with ordering made explicit if needed
bytesBase64 string or decoded text
from datetime import datetime, timezone
import json

data = {"created_at": datetime(2026, 9, 30, 12, tzinfo=timezone.utc)}

try:
    json.dumps(data)
except TypeError as exc:
    print(exc)  # Object of type datetime is not JSON serializable

Choose a representation that the reader of the JSON can understand. A timezone-aware datetime can become an ISO-8601 string; a Decimal can become a string when its exact decimal digits matter. Sorting a set produces a stable array only when its members are comparable.

Use default= carefully

A default function can centralize a conversion rule, but it should be narrow. Converting every unknown object with str() makes output succeed while losing useful type information. Prefer a clear representation that another program can understand.

from decimal import Decimal

def encode(value):
    if isinstance(value, datetime):
        return value.isoformat()
    if isinstance(value, Decimal):
        return str(value)
    raise TypeError(f"Unsupported type: {type(value).__name__}")

data["price"] = Decimal("19.90")
print(json.dumps(data, default=encode))
# {"created_at": "2026-09-30T12:00:00+00:00", "price": "19.90"}

For strict JSON, also consider allow_nan=False: Python otherwise writes non-standard NaN and Infinity values.

A datetime object and a copied datetime representation are different inputs

Inside Python, call isoformat() on a datetime object or use a narrow encoder such as the one above. In a copied log line, there is no object to call: the browser reads the text of a supported representation.

{'created_at': datetime.datetime(2026, 10, 19, 9, 30, 0, 123456), 'day': datetime.date(2026, 10, 19)}

The browser output is:

{"created_at": "2026-10-19T09:30:00.123456", "day": "2026-10-19"}

Open this datetime example in the converter. The parser recognizes these positional arguments without executing a call. The six fractional digits represent microseconds. No UTC marker or offset is added because the input supplies no timezone.

When a timezone appears in the log

A representation containing tzinfo=datetime.timezone.utc is outside this browser parser's supported syntax. Do not remove the timezone merely to make parsing succeed: that changes what the value tells its reader. Serialize the original object with isoformat() in Python instead; the UTC example earlier retains +00:00.

If the original program is unavailable, preserve the raw log and determine its timezone convention before translating it. A timestamp without an offset does not establish an instant in UTC.

A set becomes an array, not a JSON set

The browser maps a pasted set representation to an array. Try a payload containing a set and a tuple: both become arrays, so neither the original container type nor set semantics can be recovered from the JSON alone. In Python, converting a set to a list resolves serialization, but use an explicit ordering rule when stable output matters. Do not assume mixed strings and numbers can be sorted together.

See the standard encoder's supported types and this converter's limits before choosing a representation for an API.

Before encoding large identifiers or exact decimal amounts, choose a representation that preserves their precision across consumers.

By Python JSON Formatter ·