cocoindex-io/cocoindex · error · TypeError
{type(obj).__name__} cannot be used as a memoization key. Th
Error message
{type(obj).__name__} cannot be used as a memoization key. This type maintains internal state that is incompatible with memoization. What it means
CocoIndex memoization fingerprints arguments to build a memoization key. Objects of types explicitly registered via coco.register_not_memo_keyable() are rejected because they carry internal state (e.g. open files, RNGs, generators) that would make an identical key even though the object differs. A TypeError is raised at call time when such an object is passed to a memoized function.
Source
Thrown at python/cocoindex/_internal/memo_fingerprint.py:224
_memo_fns[typ] = _MemoFns(key_fn, state_fn)
def register_not_memo_keyable(typ: type) -> None:
"""Register a type as not memo-keyable.
Use this for third-party types that maintain internal state incompatible
with memoization, but which you cannot modify to inherit from `NotMemoKeyable`.
Example:
import cocoindex as coco
from some_library import StatefulGenerator
coco.register_not_memo_keyable(StatefulGenerator)
"""
def _raise_not_memo_keyable(obj: object) -> typing.NoReturn:
raise TypeError(
f"{type(obj).__name__} cannot be used as a memoization key. "
"This type maintains internal state that is incompatible with memoization."
)
_memo_fns[typ] = _MemoFns(_raise_not_memo_keyable)
def unregister_memo_key_function(typ: type) -> None:
"""Remove a previously registered memo key function (best-effort)."""
_memo_fns.pop(typ, None)
def _stable_sort_key(v: Fingerprintable) -> tuple[typing.Any, ...]:
"""Return a totally-ordered key for canonical values.
This is used to deterministically sort dict/set canonical encodings without
relying on Python comparing heterogeneous values directly.View on GitHub (pinned to e84aa99b32)
Solutions
- Remove the stateful object from the memoized function's arguments and pass only immutable, fingerprintable values (str, int, bytes, dataclasses of such).
- Pass a stable key derived from the object (e.g. its path, seed, or id) instead of the object itself.
- If the type is actually safe to key, remove it from the register_not_memo_keyable() registration in your own code.
- Disable memoization (memo=False) for functions that must accept stateful objects.
Example fix
// before
@coco.fn(memo=True)
async def run(gen: StatefulGenerator) -> int:
return gen.next()
run(StatefulGenerator())
// after
@coco.fn(memo=True)
async def run(seed: int) -> int:
gen = StatefulGenerator(seed)
return gen.next()
run(42) Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(arg, StatefulGenerator):
raise ValueError("stateful object cannot be a memoized argument") 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)) Try / catch
try:
result = await memoized_fn(arg)
except TypeError as e:
if "memoization key" in str(e):
result = await run_without_memo(arg)
else:
raise Prevention
- Only pass immutable primitives or dataclasses of primitives to memoized functions
- Never pass generators, streams, or connection objects as memoized arguments
- Inspect register_not_memo_keyable registrations before choosing argument types
When it happens
Trigger: Passing an instance of a type registered with coco.register_not_memo_keyable() (like StatefulGenerator in the docstring example) as an argument to a function decorated with @coco.fn(memo=True).
Common situations: Developers wrapping stateful objects — generators, file handles, streams, connection objects — as arguments to memoized functions, often after the library author or their own code deliberately excluded that type from memoization keys.
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
- Unsupported type for memoization key: {type(obj)!r}. Provide
- 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/bbc98099a2ae4ab5.
Report an issue: GitHub.