cocoindex-io/cocoindex · error · NotImplementedError

Cannot serialize {type(obj).__name__}

Error message

Cannot serialize {type(obj).__name__}

What it means

serde.py's msgspec encoder uses an enc_hook to serialize types msgspec does not natively handle. It supports registered safe-picklable globals and Pydantic models; anything else raises NotImplementedError('Cannot serialize <TypeName>'). The error means the object's type is not on the encoder's allowlist.

Source

Thrown at python/cocoindex/_internal/serde.py:281


# ---------------------------------------------------------------------------
# Serialization hooks (cross-pollination bridge)
# ---------------------------------------------------------------------------


def _enc_hook(obj: Any) -> Any:
    """Msgspec enc_hook: handles types msgspec can't encode natively."""
    # C: Quarantine pickle types (check first — explicit opt-in wins)
    if type(obj) in _SERIALIZE_BY_PICKLE_TYPES:
        return msgspec.msgpack.Ext(100, _strict_pickle_dumps(obj))
    key = (type(obj).__module__, type(obj).__qualname__)
    if key in _UNPICKLE_SAFE_GLOBALS:
        return msgspec.msgpack.Ext(100, _strict_pickle_dumps(obj))
    # B: Bridge Pydantic into msgspec
    if _is_pydantic_instance(obj):
        return obj.model_dump(mode="json")
    raise NotImplementedError(f"Cannot serialize {type(obj).__name__}")


_msgspec_encoder = msgspec.msgpack.Encoder(enc_hook=_enc_hook)


# ---------------------------------------------------------------------------
# Deserialization hooks
# ---------------------------------------------------------------------------


def _ext_hook(code: int, data: memoryview) -> Any:  # type: ignore[type-arg]
    """Un-quarantine pickle inside msgspec payloads."""
    if code == 100:
        return _RestrictedUnpickler(io.BytesIO(bytes(data))).load()
    raise ValueError(f"Unknown extension code: {code}")


def _dec_hook(type_hint: Any, obj: Any) -> Any:

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Register the type in _UNPICKLE_SAFE_GLOBALS (or the corresponding registration API) so it is pickled via the strict pickle path.
  2. Convert the object to a supported type (Pydantic model, dict of primitives, bytes) before serialization.
  3. Implement serialization support by making the value a Pydantic model, which the encoder bridges via model_dump(mode='json').
  4. Catch NotImplementedError at the boundary and store a fallback plain-data representation.

Example fix

// before
return MyCustomClass(x=1)  # NotImplementedError from _enc_hook

// after
from pydantic import BaseModel
class Result(BaseModel):
    x: int
return Result(x=1)  # serialized via model_dump
Defensive patterns

Strategy: try-catch

Validate before calling

def is_serializable(obj: object) -> bool:
    from cocoindex._internal import serde
    key = (type(obj).__module__, type(obj).__qualname__)
    return key in serde._UNPICKLE_SAFE_GLOBALS or serde._is_pydantic_instance(obj)

Type guard

def is_encodable(obj: object) -> bool:
    return isinstance(obj, (str, int, float, bool, type(None), bytes, list, dict)) \
        or hasattr(obj, "model_dump")  # pydantic

Try / catch

try:
    payload = encode(value)
except NotImplementedError as e:
    logging.warning("unserializable value replaced: %s", e)
    payload = encode(str(value))

Prevention

When it happens

Trigger: Returning or storing an object of an unregistered custom class (e.g. arbitrary dataclass-like types, third-party objects) from a function whose result is serialized to msgpack — exercised directly by test_unregistered_nested_raises for nested unregistered values.

Common situations: Returning custom classes, numpy arrays beyond supported kinds, datetime-like third-party types, or nested containers holding unregistered objects through target-state or memo result serialization.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/c5fe116af314ba40. Report an issue: GitHub.