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
- Add a __coco_memo_key__() method to the class returning a stable, hashable representation of the identity-relevant state.
- Call coco.register_memo_key_function(Type, fn) to register a key function for types you do not own.
- Pass a fingerprintable proxy (str path, int seed, tuple of primitives) instead of the unpicklable object.
- 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
- Define __coco_memo_key__() on any custom class used as a memoized argument
- Prefer passing stable identifiers instead of live objects
- Never pass lambdas, locks, sockets, or asyncio primitives to memoized functions
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
- {type(obj).__name__} cannot be used as a memoization key. Th
- coco.use_state() cannot be called inside a memoized function
- Memo state function returned an awaitable from a sync contex
- timeout() requires a datetime.timedelta
- memo_key transform for *args must return tuple, got {type(va
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/2681be796ddab699.
Report an issue: GitHub.