cocoindex-io/cocoindex · error · RuntimeError
LiveComponentOperator is no longer active. Operator methods
Error message
LiveComponentOperator is no longer active. Operator methods are only valid inside the body of process_live.
What it means
A LiveComponentOperator is detached (its _controller set to None) once the process_live body finishes. Any operator method afterward — update, update_full, delete, mark_ready, state reads/writes — raises RuntimeError because the operator is only valid within the process_live body scope.
Source
Thrown at python/cocoindex/_internal/live_component.py:268
self._env = env
self._path = path
def _detach(self) -> None:
"""Release the Rust controller; subsequent operator calls raise.
Called by ``_process_live_wrapper`` in a ``finally`` block once
``process_live`` returns. After detach, the operator is usable only
for inspecting its own metadata (``_env``, ``_path``); the
controller-backed methods (:meth:`update_full`, :meth:`update`,
:meth:`delete`, :meth:`mark_ready`) raise :class:`RuntimeError`.
"""
self._controller = None
def _require_controller(self) -> core.LiveComponentController:
"""Return the controller or raise if already detached."""
ctrl = self._controller
if ctrl is None:
raise RuntimeError(
"LiveComponentOperator is no longer active. Operator "
"methods are only valid inside the body of process_live."
)
return ctrl
def _resolve_exception_handler(self) -> Callable[[str], Awaitable[None]]:
"""Build a resolver for the parent's exception handler chain.
Delegates to :meth:`ComponentContext.resolve_exception_handler`
— the same path used by ``coco.mount`` / ``coco.mount_each`` —
so component-failure logs go through one canonical Python
fallback. Always non-None. Used both by :meth:`update_full`
(passes to Rust as ``on_error``) and :meth:`report_exception`
(invokes directly with a stringified exception).
"""
return get_context_from_ctx().resolve_exception_handler(
stable_path=self._path.to_string(),
processor_name=type(self._instance).__name__,View on GitHub (pinned to e84aa99b32)
Solutions
- Perform all operator calls inside the process_live body; await them before returning.
- Do not store the operator beyond the body's lifetime; capture needed data instead.
- Re-enter process_live to get a fresh operator for new updates.
Example fix
// before
async def body(op):
tasks.append(asyncio.create_task(do_update(op)))
// after
async def body(op):
await do_update(op) # finish within the body Defensive patterns
Strategy: try-catch
Validate before calling
if operator._controller is None:
raise RuntimeError("operator detached; re-enter process_live") Type guard
def is_active(op) -> bool: return getattr(op, '_controller', None) is not None
Try / catch
try:
await op.update(key, fn, args)
except RuntimeError as e:
if "no longer active" in str(e):
schedule_in_next_process_live(fn, args) Prevention
- Never store the process_live operator beyond the body; await all calls inside it.
- Avoid background tasks that outlive the process_live body and touch the operator.
When it happens
Trigger: Storing the operator passed to process_live in a variable/closure and calling op.update()/op.delete()/etc. after the process_live body returns; using the operator from another task or a later callback.
Common situations: Keeping a reference to the operator on self or in a global for later use; spawning a background task inside process_live that outlives the body and touches the operator.
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
- No ComponentContext available. This function must be called
- {api_name}() is not allowed inside process_live; use operato
- LiveMapFeed sources require live mode. Pass live=True to app
- use_mount() requires a ComponentSubpath when the function ha
- LiveComponent classes cannot be used with use_mount(). Use m
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/078a4f6c3564cb01.
Report an issue: GitHub.