pallets/flask · error · TypeError
Object of type {type(o).__name__} is not JSON serializable
Error message
Object of type {type(o).__name__} is not JSON serializable What it means
Raised by Flask's DefaultJSONProvider fallback serializer (`_default` in src/flask/json/provider.py) when an object reaches the end of its type-conversion chain. Flask extends stdlib json with support for date/datetime (RFC 822 strings), Decimal, UUID, dataclasses, and objects with `__html__` (Markup); anything else raises this TypeError because Python's `json.dumps` has no representation for it.
Source
Thrown at src/flask/json/provider.py:121
"""
obj = self._prepare_response_obj(args, kwargs)
return self._app.response_class(self.dumps(obj), mimetype="application/json")
def _default(o: t.Any) -> t.Any:
if isinstance(o, date):
return http_date(o)
if isinstance(o, (decimal.Decimal, uuid.UUID)):
return str(o)
if dataclasses and dataclasses.is_dataclass(o):
return dataclasses.asdict(o) # type: ignore[arg-type]
if hasattr(o, "__html__"):
return str(o.__html__())
raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
class DefaultJSONProvider(JSONProvider):
"""Provide JSON operations using Python's built-in :mod:`json`
library. Serializes the following additional data types:
- :class:`datetime.datetime` and :class:`datetime.date` are
serialized to :rfc:`822` strings. This is the same as the HTTP
date format.
- :class:`uuid.UUID` is serialized to a string.
- :class:`dataclasses.dataclass` is passed to
:func:`dataclasses.asdict`.
- :class:`~markupsafe.Markup` (or any object with a ``__html__``
method) will call the ``__html__`` method to get a string.
"""
default: t.Callable[[t.Any], t.Any] = staticmethod(_default)
"""Apply this function to any object that :meth:`json.dumps` doesView on GitHub ↗ (pinned to 6a2f545bfd)
Solutions
- Convert the offending object to a JSON-native type before jsonify: `list(my_set)`, `my_bytes.decode()`, `int(np_value)`, or a dict via a `to_dict()` method / marshmallow / pydantic `.model_dump()`.
- Subclass DefaultJSONProvider, override `default()` to handle your types, and set `app.json = MyProvider(app)` (Flask 2.2+).
- For dataclass-like models, define the model as a `@dataclass` or give it a `__html__`-free `to_dict()` and serialize that.
- On Flask <2.2, set `app.json_encoder` to a custom `json.JSONEncoder` subclass instead.
Example fix
# before
return jsonify({"ids": {1, 2, 3}}) # TypeError: Object of type set is not JSON serializable
# after
return jsonify({"ids": sorted({1, 2, 3})})
# or globally (Flask 2.2+):
class MyJSONProvider(DefaultJSONProvider):
@staticmethod
def default(o):
if isinstance(o, set):
return list(o)
return DefaultJSONProvider.default(o)
app.json = MyJSONProvider(app) Defensive patterns
Strategy: validation
Validate before calling
import json
def is_json_safe(obj):
try:
json.dumps(obj, default=str) # probe
return True
except TypeError:
return False
# Better: convert before passing to jsonify
from dataclasses import asdict, is_dataclass
payload = asdict(obj) if is_dataclass(obj) else obj Type guard
def is_serializable(o):
return isinstance(o, (dict, list, tuple, str, int, float, bool, type(None))) Try / catch
try:
return jsonify(data)
except TypeError:
app.logger.exception('non-serializable payload')
return jsonify({'error': 'internal serialization error'}), 500 Prevention
- Convert ORM models, datetimes, Decimals, and dataclasses to plain dicts/strings before calling jsonify()
- Register a custom JSONProvider (subclass DefaultJSONProvider and override default()) for domain types used app-wide
- Return only primitives, dicts, and lists from view functions
- Add a serialization layer (marshmallow/pydantic) so views never pass raw objects to jsonify
When it happens
Trigger: Calling `jsonify(obj)`, `flask.json.dumps(obj)`, or returning a dict/list from a view that contains an unsupported type — e.g. a set, bytes, a generator, a SQLAlchemy model instance, a numpy int64/float32/ndarray, a custom class, or a Decimal-wrapping proxy that isn't one of the handled types.
Common situations: Returning SQLAlchemy ORM objects or query results directly from a route; passing numpy/pandas values from data-science code into jsonify; serializing sets built for dedup; returning bytes from crypto/file APIs; after upgrading to Flask 2.2+ where the custom-JSONEncoder pattern (`app.json_encoder`) was deprecated in favor of providers, breaking old custom encoders.
Related errors
- Tag '{key}' is already registered.
- The view function did not return a valid response. The retur
- Working outside of application context. Attempted to use fu
- Working outside of request context. Attempted to use functi
- The session is unavailable because no secret key was set. S
AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31).
Data as JSON: /data/errors/d69686dda339bade.json.
Report an issue: GitHub ↗.