cocoindex-io/cocoindex · error · RuntimeError

coco.use_state() cannot be called inside a `with coco.compon

Error message

coco.use_state() cannot be called inside a `with coco.component_subpath()` block

What it means

use_state() attaches state to the current processing component's stable path. Inside a `with coco.component_subpath()` block the ambient path is temporarily re-routed, so state would be keyed to the wrong path; the API detects this mismatch and refuses.

Source

Thrown at python/cocoindex/_internal/api.py:862

    Example::

        # Plain (value typed as Any)
        counter = coco.use_state("counter", 0)

        # Typed — handle.value is Cursor, with full type inference
        @dataclass
        class Cursor:
            pos: int
            tag: str

        cur = coco.use_state("cursor", type_hint=Cursor, initial_value=Cursor(0, "init"))
        cur.value.pos += 1
        cur.value = Cursor(cur.value.pos, "next")
    """
    ctx = get_context_from_ctx()
    if ctx._core_path != ctx._core_processor_ctx.stable_path:
        raise RuntimeError(
            "coco.use_state() cannot be called inside a `with coco.component_subpath()` block"
        )

    if ctx._in_memo_fn:
        raise RuntimeError(
            "coco.use_state() cannot be called inside a memoized function"
        )
    try:
        # initial_value passed unserialized; engine core drops it if a value is
        # already stored on the previous run for this key.
        stored = ctx._core_processor_ctx.use_state(key, initial_value)
    except ValueError as e:
        # Rust client errors surface as ValueError; normalize to RuntimeError so
        # all use_state usage errors have a consistent type for callers.
        raise RuntimeError(str(e)) from None
    if type_hint is not None:
        deserializer = get_deserialize_fn(
            type_hint,  # type: ignore[arg-type]  # type objects are hashable at runtime

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Move the coco.use_state() call outside the `with coco.component_subpath()` block
  2. If state is needed for the nested subpath, mount it as its own component (use_mount/mount) and call use_state within that component

Example fix

// before
with coco.component_subpath("phase"):
    cur = coco.use_state("cursor", initial_value=Cursor(0, "init"))
// after
cur = coco.use_state("cursor", initial_value=Cursor(0, "init"))
with coco.component_subpath("phase"):
    ...
Defensive patterns

Strategy: validation

Validate before calling

# call use_state before entering any component_subpath block
state = coco.use_state("cursor", initial_value=Cursor(0, "init"))
with coco.component_subpath("phase"):
    ...  # no use_state here

Try / catch

try:
    cur = coco.use_state("cursor", initial_value=Cursor(0, "init"))
except RuntimeError as e:
    if "component_subpath()" in str(e):
        raise  # restructure: move use_state outside the with-block

Prevention

When it happens

Trigger: Calling coco.use_state(...) on the current component context while inside a `with coco.component_subpath(...):` block, where ctx._core_path differs from the processor's stable_path.

Common situations: Wrapping a section of a component body in component_subpath() to namespace nested mounts, and accidentally calling use_state() inside that block; reworking code that moved use_state inside the with-block during refactoring.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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