TypeError: Object of Type int64 Is Not JSON Serializable (tested)

This is one of the most common "not JSON serializable" errors in practice, because it hits anyone passing numpy or pandas data straight into json.dumps(). We measured which numpy types break it, which surprisingly don't, and the fastest fix.

1. The error, with numpy's integer, boolean and array types

import json, numpy as np

json.dumps(np.int64(5))
TypeError: Object of type int64 is not JSON serializable

json.dumps(np.bool_(True))
TypeError: Object of type bool is not JSON serializable

json.dumps(np.array([1, 2, 3]))
TypeError: Object of type ndarray is not JSON serializable

Measured: this is the numpy-specific case of the general "not JSON serializable" error — json.dumps() only knows Python's own built-in int, float, and bool, and numpy's types, despite looking and behaving like numbers, are distinct classes it's never heard of. The np.bool_ case is a little confusing: the message says "type bool," not "type bool_" or "numpy.bool_" — numpy 2.x renamed the type to numpy.bool internally, but it's still not the same class as Python's built-in bool.

2. The surprise: np.float64 works fine, with no fix needed

json.dumps(np.float64(1.5))
'1.5'

isinstance(np.float64(1.5), float)
True

isinstance(np.int64(5), int)
False

Measured: numpy.float64 is actually a subclass of Python's built-in float, so json.dumps() accepts it with zero error and zero special handling. numpy.int64 and numpy.bool_ are not subclasses of int or bool — this asymmetry is exactly why a codebase can serialize numpy floats for months and then break the first time an integer column shows up.

3. The fastest one-off fix: convert before dumping

json.dumps(int(np.int64(5)))
'5'

json.dumps(np.array([1, 2, 3]).tolist())
'[1, 2, 3]'

Measured: wrapping a scalar in int() and calling .tolist() on an array both work immediately — no custom code needed for a one-off value. This doesn't scale to a whole dict full of numpy types, though.

4. The scalable fix: a default= encoder for numpy types

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        if isinstance(obj, np.floating):
            return float(obj)
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return super().default(obj)

json.dumps({"a": np.int64(1), "b": np.array([1, 2])}, cls=NumpyEncoder)
'{"a": 1, "b": [1, 2]}'

Measured: np.integer and np.floating are numpy's own abstract base classes that every specific width (int8 through int64, float16 through float64) inherits from, so checking against those two instead of listing every width individually covers all of them in one encoder. This handles arbitrarily nested dicts and lists, unlike the one-off conversions above, since json.dumps() calls default() automatically for every value it doesn't natively recognize, however deep.

5. What about pandas?

We measured that pandas 3.0.6's own DataFrame.to_dict("records") already converts numpy scalars to plain Python int/float automatically, so json.dumps() on that output worked with no error in our test. The numpy error above typically shows up when numpy arrays or scalars are used directly — a model's raw prediction output, a NumPy computation result, or df["col"].values (which returns a raw ndarray, unlike df["col"].tolist()) — rather than through pandas' own dict conversion.

Frequently asked questions

Why does json.dumps() reject numpy.int64 but accept a plain Python int?

We confirmed numpy.int64 is a distinct class that does not subclass Python's built-in int (isinstance(np.int64(5), int) is False), so json.dumps() — which only recognizes the built-in types — doesn't know how to serialize it, even though it behaves like a number.

Why does json.dumps() work fine on a numpy.float64 value with no fix?

Because we measured that numpy.float64, unlike numpy.int64, actually is a subclass of Python's built-in float (isinstance returns True) — so json.dumps() treats it as a regular float with no error, which is why this bug often surfaces only when an integer column appears after months of floats working fine.

What's the fastest fix for a single numpy value that won't serialize?

We tested wrapping it in Python's own constructor first — int(np.int64(x)) for a scalar, or .tolist() for a numpy array — both convert to plain Python types that json.dumps() accepts natively, with no custom encoder needed for a one-off value.

What's the right way to handle numpy types throughout a whole dict?

We built and tested a json.JSONEncoder subclass checking isinstance against np.integer and np.floating (numpy's abstract base classes covering every integer/float width) plus np.ndarray, passed as cls= to json.dumps() — it gets called automatically for every non-native value at any nesting depth.

Does converting a pandas DataFrame to a dict avoid this numpy serialization error?

In our test with pandas 3.0.6, yes — DataFrame.to_dict('records') already converted int64/float64 columns to plain Python int/float automatically; the error is more likely to show up on raw numpy arrays or scalars used directly, such as a model's output or df['col'].values.

Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5, numpy 2.5.3 and pandas 3.0.6, calling json.dumps() directly on numpy scalar and array types and printing the exact exception text. Every message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python's json, numpy and pandas are free libraries.