Skip to content

How to Resolve Python "TypeError: Object of type Decimal is not JSON serializable"

Fix the Python JSON serialization error when working with decimal.Decimal objects by converting them to strings or using a custom encoder to ensure precise decimal values are properly formatted.

When working with precise numerical data in Python using the decimal module, you might encounter the TypeError: Object of type Decimal is not JSON serializable error when trying to serialize data containing Decimal objects into a JSON string using the standard json library. This happens because the default JSON encoder doesn't natively recognize or know how to convert Decimal objects.

This guide explains why this error occurs and details effective methods to serialize Decimal objects correctly.

Understanding the Error: JSON Serializable Types

JSON (JavaScript Object Notation) has a limited set of standard data types: objects (maps/dictionaries), arrays (lists/tuples), strings, numbers (integers/floats), booleans (true/false), and null. Python's built-in json module knows how to convert standard Python types (dict, list, tuple, str, int, float, bool, None) into their corresponding JSON representations.

However, specialized types like decimal.Decimal, datetime.datetime, or custom class instances are not directly supported by the default encoder.

The Cause: json.dumps() and Decimal Objects

The TypeError occurs because the json.dumps() function (which serializes a Python object into a JSON formatted string) encounters a Decimal object and doesn't have a built-in rule for converting it to a standard JSON type.

import json
from decimal import Decimal

price = Decimal('19.99')
data = {'item': 'Book', 'price': price}

print(f"Data contains type: {type(data['price'])}") # Output: <class 'decimal.Decimal'>

try:
  json_output = json.dumps(data)
  print(json_output)
except TypeError as e:
  print(e)

The json.dumps() function accepts a default keyword argument. You can provide a function to default that will be called for any object the encoder doesn't recognize. A simple and effective solution for Decimal is to convert it to a string, which preserves its exact precision.

import json
from decimal import Decimal

price = Decimal('19.9900') # Note the trailing zeros
data = {'item': 'Book', 'price': price}

json_output = json.dumps(data, default=str)

print(f"Serialized JSON (Decimal as string): {json_output}")

print(f"Output type: {type(json_output)}") # Output: <class 'str'>
  • default=str: When json.dumps encounters the Decimal object price, it calls str(price), which returns "19.9900". This string is JSON serializable.

Solution 2: Creating a Custom JSONEncoder Subclass

For more complex scenarios or reusable logic, you can create a custom encoder by subclassing json.JSONEncoder and overriding its default() method.

import json
from decimal import Decimal

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return str(obj)
        return super(DecimalEncoder, self).default(obj)

price = Decimal('0.1') # A value often imprecise as float
inventory = [Decimal('1.5'), Decimal('2.0')]
data = {'cost': price, 'stock': inventory}

json_output = json.dumps(data, cls=DecimalEncoder)

print(f"Serialized JSON (Custom Encoder): {json_output}")
  • The default(self, obj) method receives objects the standard encoder can't handle.
  • We check if obj is a Decimal. If so, we return str(obj).
  • Otherwise, we call the parent class's default method (super().default(obj)) to handle standard types or raise the appropriate TypeError for other unhandled types.
  • You pass your custom class to json.dumps() using the cls argument: cls=DecimalEncoder.

Solution 3: Using the simplejson Library

The third-party simplejson library is an alternative JSON encoder/decoder that offers more features, including native support for Decimal objects (often enabled by default).

  1. Install simplejson:
    pip install simplejson
  2. Use simplejson.dumps():
    from decimal import Decimal
    import simplejson as json
    
    price = Decimal('19.99')
    data = {'item': 'Book', 'price': price}
    
    json_output = json.dumps(data, use_decimal=True)
    
    print(f"Serialized JSON (simplejson): {json_output}")
    
    print(f"Output type: {type(json_output)}") # Output: <class 'str'>

Important Consideration: String vs. Float for Precision

  • Why str? (Solutions 1 & 2): decimal.Decimal is used for exact precision, which standard floating-point numbers often lack (e.g., 0.1 + 0.2 is not exactly 0.3 in binary floating-point). JSON's number type is typically implemented using floats. Serializing a Decimal as a string ("19.9900") guarantees that the exact value is transmitted without potential floating-point rounding errors. The receiving system must then be aware that this string represents a decimal and parse it accordingly. This is the standard way to exchange high-precision decimal values via JSON.
  • Why float? (simplejson default): If the precision loss associated with standard floats is acceptable for your application, or if the receiving system expects JSON numbers directly, using simplejson (or potentially default=float in json.dumps, though less common for Decimal) might be simpler. However, you lose the guarantee of exact precision.

Conclusion

The TypeError: Object of type Decimal is not JSON serializable occurs because Python's default json encoder doesn't natively support the decimal.Decimal type.

The recommended solutions are:

  1. Use json.dumps(data, default=str): This converts Decimal objects to strings, preserving their exact precision, which is crucial for financial or scientific data. This is generally the best practice.
  2. Create a custom JSONEncoder subclass: Override the default method to convert Decimal to str. This is useful for reusable or more complex serialization logic.
  3. Use the simplejson library: It offers native Decimal support (usually serializing as a JSON number/float), which might be convenient if exact precision is less critical or if the receiver expects numbers.

Choose the method based on whether preserving the exact precision of the Decimal (by converting to a string) is required for your application.

Navigation