roboflow/supervision · error · TypeError

Object of type {type(value).__name__} is not JSON serializab

Error message

Object of type {type(value).__name__} is not JSON serializable

What it means

Raised by JSONSink's default serializer when json.dump encounters a value that is neither a np.generic scalar nor an np.ndarray. The hook exists specifically to convert NumPy types to plain Python; any other non-JSON-native object (datetime, dataclass, torch tensor, custom class) falls through to this TypeError.

Source

Thrown at src/supervision/detection/tools/json_sink.py:107

        Called as the ``default`` hook by :func:`json.dump`. Converts
        :class:`numpy.generic` scalars via ``.item()`` and
        :class:`numpy.ndarray` instances via ``.tolist()``.

        Args:
            value: Object the standard JSON encoder could not serialize.

        Returns:
            A Python scalar or nested list equivalent of ``value``.

        Raises:
            TypeError: If ``value`` is neither a NumPy scalar nor an ndarray.
        """
        if isinstance(value, np.generic):
            return value.item()
        if isinstance(value, np.ndarray):
            return value.tolist()
        raise TypeError(
            f"Object of type {type(value).__name__} is not JSON serializable"
        )

    def write_and_close(self) -> None:
        """
        Write and close the JSON file.
        """
        if self.file:
            try:
                json.dump(
                    self.data, self.file, indent=4, default=JSONSink._json_default
                )
            finally:
                self.file.close()

    @staticmethod
    def _slice_value(value: Any, i: int, n: int) -> Any:
        """

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Convert non-NumPy objects before appending: str() or .isoformat() for datetimes, dataclasses.asdict() for dataclasses, .tolist() for torch tensors.
  2. Restrict appended values to JSON-native types (str/int/float/bool/None/list/dict) plus NumPy scalars and arrays.
  3. If you must keep arbitrary types, pre-serialize them yourself and store the string form.

Example fix

# before
sink.append(frame=1, at=datetime.now(), class_name='person')  # TypeError

# after
sink.append(frame=1, at=datetime.now().isoformat(), class_name='person')
Defensive patterns

Strategy: validation

Validate before calling

import dataclasses
import datetime as dt
import numpy as np

def jsonable(v):
    if isinstance(v, (dt.date, dt.datetime)):
        return v.isoformat()
    if isinstance(v, np.generic):
        return v.item()
    if isinstance(v, np.ndarray):
        return v.tolist()
    if dataclasses.is_dataclass(v):
        return jsonable(dataclasses.asdict(v))
    if hasattr(v, 'tolist'):
        return v.tolist()
    return v

sink.append(**{k: jsonable(v) for k, v in payload.items()})

Type guard

def is_json_sink_safe(v) -> bool:
    import dataclasses, datetime as dt
    return v is None or isinstance(v, (str, int, float, bool, list, dict, np.generic, np.ndarray)) or isinstance(v, (dt.date, dt.datetime)) and False

Try / catch

try:
    sink.append(frame=i, **payload)
except TypeError as err:
    if 'not JSON serializable' in str(err):
        payload = {k: str(v) for k, v in payload.items()}
        sink.append(frame=i, **payload)
    else:
        raise

Prevention

When it happens

Trigger: Appending data to JSONSink that contains a Python datetime/date, a torch.Tensor, a dataclass instance, a set, or any custom object — via sink.append(...) where one of the payload values is not JSON-native or NumPy.

Common situations: Logging detection metadata such as timestamps (datetime.now()), model objects, or tuples of custom classes alongside frame data; migrating from a sink that used str() coercion to JSONSink which does not.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/75394db5ac0959c4. Report an issue: GitHub.