Skip to content
Happy Programming Guide
Start learning
Python

Object of Type int64 Is Not JSON Serializable

NumPy and pandas numbers are not Python numbers, and json.dumps refuses them. Here are four fixes, from a one-line conversion to a reusable encoder.

A laptop computer on a table

TypeError: Object of type int64 is not JSON serializable means you are trying to convert a NumPy or pandas value to JSON. numpy.int64 looks and behaves like an integer, but it is a different type, and Python’s json module only knows about the built-in ones. The fix is to convert before serialising — and there are four ways to do it depending on how much data you have.

Reproducing it#

Python
import json
import numpy as np

value = np.int64(42)

print(value + 1)          # 43 - behaves like an int
print(isinstance(value, int))   # False on most platforms

json.dumps({"count": value})
Output
TypeError: Object of type int64 is not JSON serializable

NumPy uses its own fixed-width types for speed and predictable memory layout. Python’s int is arbitrary precision and stored quite differently. The json module checks types exactly, so a lookalike is not enough.

Fix 1: convert the single value#

Python
json.dumps({"count": int(value)})           # {"count": 42}

# or, for any NumPy scalar
json.dumps({"count": value.item()})

.item() is the general answer: it converts any NumPy scalar to its nearest Python equivalent, so it works for integers, floats and booleans alike without you having to know which you have.

Fix 2: convert a whole structure#

When the values are buried in a dictionary or list, walk it:

Python
import numpy as np


def to_builtin(obj):
    if isinstance(obj, dict):
        return {key: to_builtin(value) for key, value in obj.items()}
    if isinstance(obj, (list, tuple)):
        return [to_builtin(item) for item in obj]
    if isinstance(obj, np.ndarray):
        return obj.tolist()
    if isinstance(obj, np.generic):     # covers every NumPy scalar type
        return obj.item()
    return obj


data = {"counts": np.array([1, 2, 3]), "mean": np.float64(2.0)}
print(json.dumps(to_builtin(data)))
Output
{"counts": [1, 2, 3], "mean": 2.0}

np.generic is the base class for every NumPy scalar, so that one branch handles int64, float32, bool_ and the rest.

Fix 3: a custom encoder (the reusable option)#

Python
import json
import numpy as np


class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        if isinstance(obj, np.generic):
            return obj.item()
        return super().default(obj)


data = {"id": np.int64(7), "scores": np.array([1.5, 2.5])}

print(json.dumps(data, cls=NumpyEncoder))
Output
{"id": 7, "scores": [1.5, 2.5]}

The default method is called only for values the encoder does not already understand, so there is no cost for ordinary data. Calling super().default(obj) at the end is important — it lets genuinely unserialisable objects still raise a clear error rather than being silently mangled.

The same thing as a function, if you prefer:

Python
def numpy_default(obj):
    if isinstance(obj, np.ndarray):
        return obj.tolist()
    if isinstance(obj, np.generic):
        return obj.item()
    raise TypeError(f"Not serialisable: {type(obj).__name__}")


json.dumps(data, default=numpy_default)

Fix 4: let pandas do it#

If the data is in a DataFrame, pandas already knows how to convert its own types:

Python
import pandas as pd

df = pd.DataFrame({"name": ["a", "b"], "count": [1, 2]})

print(df.to_json(orient="records"))
Output
[{"name":"a","count":1},{"name":"b","count":2}]

This is the cleanest route when your data starts as a DataFrame. Note that df.to_dict() does not convert the types — the values inside are still NumPy scalars, so json.dumps(df.to_dict()) raises the same error. Use to_json, or apply one of the fixes above afterwards.

The same error, other types#

Message mentions Convert with
int64, int32 int(x) or x.item()
float64, float32 float(x) or x.item()
bool_ bool(x)
ndarray x.tolist()
Timestamp, datetime x.isoformat()
Decimal float(x) or str(x)
set list(x)

A fuller encoder handling the common cases together:

Python
import datetime, decimal


class SafeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        if isinstance(obj, np.generic):
            return obj.item()
        if isinstance(obj, (datetime.datetime, datetime.date)):
            return obj.isoformat()
        if isinstance(obj, decimal.Decimal):
            return float(obj)
        if isinstance(obj, set):
            return sorted(obj)
        return super().default(obj)

NaN and infinity#

Python
json.dumps({"value": float("nan")})    # '{"value": NaN}'

Python produces this without complaint, but NaN and Infinity are not valid JSON, and strict parsers — including most browsers — will reject the result. Replace them before serialising:

Python
import math

clean = {k: (None if isinstance(v, float) and not math.isfinite(v) else v)
         for k, v in data.items()}

json.dumps(clean, allow_nan=False)     # now raises if any slipped through

Questions people ask#

Why does isinstance(np.int64(1), int) return False?

On most platforms np.int64 does not inherit from Python’s int. Confusingly, np.float64 does inherit from float, which is why float values sometimes serialise without complaint and integers do not.

Is there a performance cost to a custom encoder?

Negligible. The default method only runs for types the encoder cannot already handle, so ordinary strings and numbers take the fast path unchanged.

Should I use orjson instead?

orjson serialises NumPy types natively when you pass option=orjson.OPT_SERIALIZE_NUMPY, and it is considerably faster. Worth adopting if you are writing a lot of JSON; unnecessary for a one-off script.

How do I get the types back when reading?

JSON has no concept of int64, so you cannot — everything comes back as a plain Python type. Rebuild the NumPy array or DataFrame explicitly after loading, specifying the dtype you want.

Where to go next#

Solving Python dict TypeErrors, one message at a timeRead next

Keep reading

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *