cocoindex-io/cocoindex · error · TypeError

Unsupported type for memoization key: {type(obj)!r}. Provide

Error message

Unsupported type for memoization key: {type(obj)!r}. Provide __coco_memo_key__() or register a memo key function.

What it means

Memoization keys are built by canonicalizing every argument. When an object has no __coco_memo_key__() method, no registered memo key function, and cannot even be pickled as a fallback, the library raises TypeError because a stable key cannot be computed. This protects memoization correctness: without a stable key, cached results could be wrongly reused.

Source

Thrown at python/cocoindex/_internal/memo_fingerprint.py:366

        elts = [_canonicalize(e, _seen, state_methods) for e in obj]
        elts.sort(key=_stable_sort_key)
        return ("set", tuple(elts))

    # 5) Dataclass instances
    if _is_dataclass_instance(obj):
        return _canonicalize_dataclass(obj, _seen, state_methods)

    # 6) Pydantic v2 models
    if _is_pydantic_model(obj):
        return _canonicalize_pydantic(obj, _seen, state_methods)

    # 7) Fallback
    try:
        payload = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL)
        # Tag to avoid colliding with user-provided raw bytes.
        return ("pickle", payload)
    except Exception:
        raise TypeError(
            f"Unsupported type for memoization key: {type(obj)!r}. "
            "Provide __coco_memo_key__() or register a memo key function."
        ) from None


def _make_call_canonical(
    func: typing.Callable[..., object],
    args: tuple[object, ...],
    kwargs: dict[str, object],
    state_methods: list[StateFnEntry],
    *,
    version: str | int | None = None,
    prefix_args: tuple[object, ...] = (),
) -> Fingerprintable:
    function_identity = (
        canonical_module_name(func),
        getattr(func, "__qualname__", None),
    )

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Add a __coco_memo_key__() method to the class returning a stable, hashable representation of the identity-relevant state.
  2. Call coco.register_memo_key_function(Type, fn) to register a key function for types you do not own.
  3. Pass a fingerprintable proxy (str path, int seed, tuple of primitives) instead of the unpicklable object.
  4. Turn off memoization for that function (memo=False) if stable keying is impossible.

Example fix

// before
@coco.fn(memo=True)
async def process(conn: asyncpg.Connection) -> int: ...  # connections are unpicklable

// after
class Job:
    def __coco_memo_key__(self):
        return ("Job", self.job_id)

@coco.fn(memo=True)
async def process(job: Job) -> int: ...
Defensive patterns

Strategy: type-guard

Validate before calling

import pickle
if not hasattr(obj, "__coco_memo_key__"):
    try:
        pickle.dumps(obj)
    except Exception:
        raise ValueError(f"{type(obj).__name__} is not memo-keyable")

Type guard

def is_memo_keyable(obj: object) -> bool:
    return hasattr(obj, "__coco_memo_key__") or isinstance(obj, (str, int, float, bytes, bool, type(None), tuple, frozenset))

Try / catch

try:
    result = await memoized_fn(obj)
except TypeError as e:
    if "Unsupported type for memoization key" in str(e):
        result = await memoized_fn(extract_key(obj))
    else:
        raise

Prevention

When it happens

Trigger: Passing an object that defines no __coco_memo_key__(), is not a supported builtin/dataclass/pydantic type, and is not picklable (e.g. lambdas, open sockets, locks, generators, thread locals) as an argument to a @coco.fn(memo=True) function.

Common situations: Passing closures, local functions, database connections, asyncio objects, or third-party objects with exotic internals into memoized functions; often happens after refactoring a function signature to accept a richer object.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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