cocoindex-io/cocoindex · error · ValueError

Context key {key} already used

Error message

Context key {key} already used

What it means

ContextKey names are globally unique in a process. The constructor registers each key string in a process-wide set guarded by a lock; constructing a second ContextKey with the same string raises ValueError so that two independently-created keys can never alias the same context slot.

Source

Thrown at python/cocoindex/_internal/context_keys.py:107

        running_loop_error_msg=(
            f"Async state function on detect_change context key {key_name!r} "
            "cannot be called from a running event loop at provide() time. "
            "Use a sync state function, or provide the value outside of an "
            "async context."
        ),
    )
    return [outcome.state for outcome in outcomes]


class ContextKey(Generic[T_co]):
    __slots__ = ("_key", "_detect_change")
    _key: str
    _detect_change: bool

    def __init__(self, key: str, *, detect_change: bool = False):
        with _lock:
            if key in _used_keys:
                raise ValueError(f"Context key {key} already used")
            _used_keys.add(key)
        self._key = key
        self._detect_change = detect_change

    @property
    def detect_change(self) -> bool:
        return self._detect_change

    @property
    def key(self) -> str:
        return self._key

    def __coco_memo_key__(self) -> str:
        return self._key


class ContextProvider:
    __slots__ = (

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Define each ContextKey once at module scope and import it wherever needed
  2. Use a distinct, namespaced string for each key (e.g. "myapp.pg_pool")
  3. In tests, create the key in a fresh subprocess or pick a unique suffix per test run

Example fix

// before
key = ContextKey("db")   # second definition, same string

// after
from myapp.context_keys import DB_KEY  # single module-level definition
Defensive patterns

Strategy: validation

Validate before calling

_seen_keys: set[str] = set()
def make_key(name: str) -> str:
    if name in _seen_keys:
        raise AssertionError(f"duplicate ContextKey {name}")
    _seen_keys.add(name)
    return name

Try / catch

try:
    key = ContextKey("db_pool")
except ValueError as e:
    key = EXISTING_DB_KEY  # reuse the module-level key
    logging.warning("ContextKey reused: %s", e)

Prevention

When it happens

Trigger: Calling ContextKey("db_pool") (or any subclass/factory) twice at module level or in a function that runs multiple times — e.g. a module imported twice with different paths, a factory function invoked per-request, a test re-running module setup in the same process, or module reload.

Common situations: Defining the same key string in two modules; creating keys dynamically inside a loop or fixture; hot-reloading a module during development.

Related errors


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