pallets/flask · error · TypeError
Object of type is not JSON serializable
Error message
Object of type {type(o).__name__} is not JSON serializable What it means
_default(o) is Flask's JSON encoder fallback for objects the standard json module cannot serialize. It handles date/datetime, Decimal, UUID, dataclasses, and objects with __html__. If an object matches none of these, it raises TypeError naming the object's type. This surfaces during jsonify/dumps when your data contains an unsupported type like a SQLAlchemy model instance, a set, bytes, or a custom class.
Solutions
- Convert the object to a serializable form before jsonify: model.to_dict(), list(my_set), my_bytes.decode(), enum.value.
- Subclass DefaultJSONProvider and override _default or dumps to handle your custom types, then set app.json.
- Use marshmallow/pydantic to serialize complex objects to dicts.
Example fix
# before
@app.route('/u')
def user():
return jsonify(db.session.get(User, 1)) # User not serializable
# after
@app.route('/u')
def user():
u = db.session.get(User, 1)
return jsonify({'id': u.id, 'name': u.name}) Defensive patterns
Strategy: type-guard
Validate before calling
import dataclasses, datetime, decimal, uuid, json
def is_json_serializable(o) -> bool:
return isinstance(o, (str, int, float, bool, type(None), list, tuple, dict,
datetime.date, datetime.datetime, decimal.Decimal, uuid.UUID)) \
or (dataclasses.is_dataclass(o)) or hasattr(o, '__html__')
# validate before jsonify
def assert_serializable(obj):
json.dumps(obj, default=lambda o: (_ for _ in ()).throw(
TypeError(f'{type(o).__name__} not serializable')) if not is_json_serializable(o) else o)) Type guard
import datetime, decimal, uuid, dataclasses
def is_default_serializable(o) -> bool:
return isinstance(o, (str, int, float, bool, type(None), list, tuple, dict,
datetime.date, decimal.Decimal, uuid.UUID)) \
or dataclasses.is_dataclass(o) or hasattr(o, '__html__') Try / catch
from flask.json.provider import DefaultJSONProvider
import json
class SafeJSONProvider(DefaultJSONProvider):
def dumps(self, obj, **kw):
try:
return super().dumps(obj, **kw)
except TypeError:
return super().dumps(str(obj), **kw)
app.json = SafeJSONProvider(app) Prevention
- Convert ORM/model objects to dicts before jsonify.
- Register a custom JSONProvider.default for app-wide custom types.
- Unit-test response payloads with json.dumps to catch unserializable types early.
When it happens
Trigger: Returning jsonify(obj) where obj (or a nested value) is a type Flask does not serialize by default: a set, bytes, a custom class without __html__, a SQLAlchemy InstrumentedList, an Enum, or a Pandas DataFrame. _default is called by json.dumps for each unhandled object.
Common situations: Passing ORM objects to jsonify instead of dicts. Forgetting to convert a set to a list. Returning bytes or a custom value object. Using Enum members in API responses without a default encoder.
Related errors
- Tag ' ' is already registered.
- app.json.response() takes either args or kwargs, not both
- A valid Flask application was not obtained from
- 'after_this_request' can only be used when a request…
- Allowed methods must be a list of strings, for example…
AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11).
Data as JSON: /api/errors/d69686dda339bade.
Report an issue: GitHub.
Appendix: 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 3596b1ab61)