The TypeError: Object of type int64 is not JSON serializable is one of the most common roadblocks Python developers encounter when working with data science libraries like NumPy and Pandas alongside web frameworks such as Flask, FastAPI, or Django. bool_—that the native encoder does not recognize. int64, numpy.So naturally, this error surfaces when the standard jsonlibrary attempts to convert a Python dictionary or list into a JSON string but stumbles upon a NumPy specific data type—most frequentlynumpy. float64, or numpy.Understanding why this happens and how to fix it efficiently is essential for building strong data pipelines and APIs.
Why the Standard JSON Encoder Fails
Python’s built-in json module is designed to serialize a specific set of native Python types: dict, list, tuple, str, int, float, bool, and None. dumps()orjson.It operates on the assumption that the data structures passed to json.dump() contain only these standard types.
Even so, the scientific Python ecosystem relies heavily on NumPy for high-performance numerical computing. Take this case: accessing a single integer value from a DataFrame column defined as int64 returns a numpy.Which means when you manipulate data in a Pandas DataFrame or a NumPy array, the scalar values extracted often retain their NumPy dtype. Day to day, numPy introduces its own hierarchy of data types (dtypes) optimized for memory efficiency and vectorized operations. int64 object, not a standard Python int No workaround needed..
Because numpy.int64 is a distinct class—technically a subclass of numpy.Think about it: generic rather than Python’s built-in int—the default JSONEncoder does not know how to handle it. It lacks the logic to convert this specialized object into a valid JSON number, resulting in the familiar TypeError Surprisingly effective..
Common Scenarios Triggering the Error
This error rarely appears in isolation; it typically manifests in specific architectural patterns:
- API Response Construction: You query a database or process a DataFrame, build a dictionary payload, and return it via
jsonify(Flask) orjson.dumps. If the payload contains a column sum, a specific row value, or an aggregation result stored asint64, the serialization fails. - Logging and Monitoring: Structured logging libraries (like
python-json-logger) attempt to serialize log context dictionaries. If a metric value is a NumPy scalar, the logger crashes. - Caching Layers: Storing computed results in Redis or Memcached often requires JSON serialization. NumPy types embedded in the cache payload break the setter operation.
- Message Queues: Publishing events to RabbitMQ, Kafka, or SQS usually requires a JSON string payload. NumPy types in the event schema cause producer errors.
Solution 1: Explicit Type Casting (The Quick Fix)
The most immediate way to resolve the error for a specific variable is explicit conversion using Python’s built-in constructors. Since NumPy scalars implement the necessary protocols (like __int__, __float__), they convert cleanly.
import numpy as np
import json
# The problematic object
numpy_val = np.int64(42)
# Direct serialization fails
# json.dumps(numpy_val) # TypeError
# Explicit casting works
standard_int = int(numpy_val)
json_string = json.dumps(standard_int)
print(json_string) # Output: "42"
Pros: Simple, readable, zero dependencies. Cons: Tedious if you have nested dictionaries, large lists, or entire DataFrames. You must know exactly where the NumPy types live Easy to understand, harder to ignore..
Solution 2: Custom JSON Encoder (The solid Architectural Fix)
For applications where NumPy types appear frequently and unpredictably—such as a general-purpose API utility—subclassing json.Consider this: jSONEncoder is the professional standard. By overriding the default method, you teach the encoder how to handle NumPy generics globally.
import json
import numpy as np
class NumpyEncoder(json.So jSONEncoder):
def default(self, obj):
if isinstance(obj, np. Even so, integer):
return int(obj)
if isinstance(obj, np. floating):
return float(obj)
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, np.bool_):
return bool(obj)
# Let the base class handle everything else (or raise TypeError)
return super().
# Usage
data = {
"user_id": np.int64(101),
"score": np.float64(99.5),
"is_active": np.bool_(True),
"tags": np.array([1, 2, 3])
}
print(json.dumps(data, cls=NumpyEncoder))
# Output: {"user_id": 101, "score": 99.5, "is_active": true, "tags": [1, 2, 3]}
This approach centralizes the serialization logic. Any part of your codebase calling json.dumps(data, cls=NumpyEncoder) becomes immune to this specific TypeError. It also handles ndarray objects by converting them to native Python lists via tolist(), solving a related serialization issue simultaneously.
Integrating with Web Frameworks
- Flask: Flask’s
jsonifyuses the app’sjson_encoderattribute. You can setapp.json_encoder = NumpyEncoder(Flask < 2.0) orapp.json.provider_class(Flask >= 2.3) to make it automatic. - FastAPI / Starlette: These use
orjsonorujsonby default, which often handle NumPy types natively. If using standardjson, you can pass a customdefaultfunction tojson.dumpsinside a custom response class. - Django: The
DjangoJSONEncoderhandles many types but not NumPy. You can extendDjangoJSONEncodersimilarly and pass it toJsonResponse(encoder=MyEncoder).
Solution 3: Pandas Native Serialization (The Data Science Way)
If your workflow originates in Pandas, fighting the json module is often the wrong abstraction level. Pandas provides highly optimized, built-in serialization methods that handle dtypes, NaN/NaT representation, and orientation automatically.
DataFrame.to_json()
This is the single most effective method for converting DataFrames or Series to JSON strings.
import pandas as pd
import numpy as np
df = pd.Because of that, dataFrame({
"id": np. In real terms, array([1, 2], dtype=np. int64),
"value": np.Day to day, array([10. 5, 20.In practice, 1], dtype=np. float64),
"flag": np.
# Default orientation ('columns')
json_str = df.to_json(orient='records')
print(json_str)
# '[{"id":1,"value":10.5,"flag":true},{"id":2,"value":20.1,"flag":false}]'
Key parameters to master:
orient: Controls structure. Plus,'records'(list of dicts) is standard for APIs.'split'separates index, columns, and data (compact for large datasets). Plus,'table'preserves schema metadata. Worth adding: *date_format: Use'iso'for ISO 8601 timestamps. *default_handler: A callable for types Pandas still can't serialize (rarely needed).
to_dict() for Python Objects
If you need a native Python dictionary (e., to merge with other data before final serialization), use to_dict(orient='records'). g.This recursively converts NumPy scalars to native Python types And that's really what it comes down to..
# Returns List[Dict[str, Any]] with native Python types
1. **Analyze the Request:**
* **Goal:** Continue the article smoothly. Do not repeat previous text. Finish with a proper conclusion.
* **Input text:** A continuation of an article about handling NumPy serialization in Python (specifically `json.dumps`). The text covers Solutions 1 & 2 (Custom Encoder class, Centralized logic/Flask/FastAPI/Django integration) and Solution 3 (Pandas native serialization - `DataFrame.to_json()` and `to_dict()`). It ends mid-sentence: "### `to_dict()` for Python Objects\n\nIf you need a native Python dictionary (e.g., to merge with other data before final serialization), use `to_dict(orient='records')`. This recursively converts NumPy scalars to native Python types.\n\n```python"
* **Constraint Checklist & Confidence Score:**
1. Continue smoothly? Yes.
2. Do not repeat previous text? Yes.
3. Finish with a proper conclusion? Yes.
Confidence Score: 5/5.
2. **Determine the Next Steps:**
* Complete the code block for `to_dict()`.
* Provide a brief summary or additional tip about Pandas serialization (maybe mention `Series.to_json()` or `to_dict()` variations like `orient='list'`, `orient='index'`).
* Transition into a concluding section that summarizes the best practices for NumPy/Pandas JSON serialization.
3. **Drafting the Content:**
* *Code completion:*
```python
import pandas as pd
import numpy as np
s = pd.Even so, series(np. Now, array([1, 2, 3], dtype=np. That said, int64))
native_dict = s. Because of that, to_dict(orient='records')
print(native_dict) # [{'0': 1}, {'0': 2}, {'0': 3}] -> wait, Series index is '0'. Better example:
# Let's use a Series with named index or just show the dict output.
```
Actually, let's keep it simple and direct:
```python
s = pd.So series([1, 2, 3], dtype=np. int64)
result = s.On top of that, to_dict(orient='records')
print(result) # {0: 1, 1: 2, 2: 3} -> wait, orient='records' on a Series returns a list of dicts if it has multiple keys, but for a single key Series it returns a list of dicts with the index as key? No, `Series.to_dict(orient='records')` returns `[{'0': 1}, {'0': 2}, ...Practically speaking, ]`. Which means let's use a DataFrame or just show the standard behavior. # Better:
df = pd.Still, dataFrame({'a': np. array([1,2])})
print(df.to_dict('records'))
```
Let's just finish the thought naturally. "This recursively converts NumPy scalars to native Python types." followed by a code snippet showing how it works.
* *Expanding Solution 3:* Add a note about `orient='list'` or `orient='index'` for Series, or just point out why this is often the preferred approach over fighting the `json` module.
* *Conclusion:* Summarize the trade-offs. Custom encoders are good for general frameworks, Pandas is best for data science workflows.
4. **Refining the Output:**
* *Continuation:*
```python
import pandas as pd
import numpy as np
series = pd.Series(np.array([10, 20, 30], dtype=np.int64))
native_types = series.So to_dict(orient='records')
print(native_types) # [{'0': 10}, {'0': 20}, {'0': 30}]
```
Wait, `orient='records'` for a Series creates a list of dictionaries where each element is a dictionary containing the index value as the key. Worth adding: let's use a cleaner example. ```python
data = {"id": np.array([1, 2], dtype=np.int64)}
native_dict = pd.Series(data["id"]).to_dict(orient='records')
# Wait, that's weird.
arr = np.array([1, 2, 3], dtype=np.int64)
result = arr.to_dict(orient='records') # Actually, ndarray doesn't have to_dict.
# Let's stick to Series or DataFrame.
series = pd.Worth adding: series({"a": np. That said, int64(1), "b": np. float64(2.5)})
native_dict = series.