cocoindex-io/cocoindex · error · RuntimeError
{self._label} supports a single active watch() at a time.
Error message
{self._label} supports a single active watch() at a time. What it means
The connectorkits watch() guard enforces that only one active watch session exists per labeled resource at a time; entering the context manager twice concurrently would produce duplicated or interleaved event streams, so it raises this RuntimeError.
Source
Thrown at python/cocoindex/connectorkits/__init__.py:50
The flag resets on every exit — normal return, exception, or cancellation (a
cancelled ``await`` inside the ``with`` unwinds through ``__exit__``) — so the
feed can be re-watched sequentially after a prior ``watch()`` finishes.
A plain flag (no lock) suffices when ``watch()`` runs entirely on one event
loop, as the framework's live consumer does. A feed that already carries
equivalent "is being watched" state can guard on that instead.
"""
__slots__ = ("_label", "_active")
def __init__(self, label: str) -> None:
self._label = label
self._active = False
def __enter__(self) -> None:
if self._active:
raise RuntimeError(
f"{self._label} supports a single active watch() at a time."
)
self._active = True
def __exit__(self, *exc: object) -> None:
self._active = False
def default_subpath_name(processor_fn: Any) -> str | None:
"""Resolve the default subpath name for a mount target.
Honors an explicit ``__coco_subpath_name__`` attribute (set by wrappers
like ``coco.auto_refresh`` so the wrapper class can keep an honest
``__name__`` while still mounting under the wrapped function's name),
falling back to ``__name__``.
"""
name = getattr(processor_fn, "__coco_subpath_name__", None)
if isinstance(name, str):View on GitHub (pinned to e84aa99b32)
Solutions
- Exit the first watch() before entering another (restructure into sequential with-blocks)
- Create a separate watch handle/instance for each concurrent consumer instead of sharing one
- Serialize watch usage in the same task/thread, or fan out events from a single watch to multiple consumers
- Verify no leaked context due to an exception path that skips __exit__ (use try/finally or with-statements)
Example fix
// before
w1 = res.watch(); w2 = res.watch()
with w1, w2: # RuntimeError
// after
with res.watch():
handle_events() Defensive patterns
Strategy: try-catch
Validate before calling
if watch_handle._active:
raise RuntimeError("watch already active; exit it before re-entering") Try / catch
try:
with resource.watch():
consume()
except RuntimeError as e:
if "single active watch" in str(e):
serialize_watch_usage() # retry sequentially Prevention
- Never share one watch context manager across concurrent tasks
- Structure watch usage as strictly sequential with-blocks
- Fan out events from a single watch rather than opening multiple watches
When it happens
Trigger: Entering the same watch() context manager a second time while a previous one is still active (not __exit__-ed) — e.g. nesting two `with resource.watch():` blocks on the same object, or re-entering from another thread/task before exit.
Common situations: Refactoring code that calls watch() in two helper functions both entered simultaneously; spawning concurrent tasks that each enter the same watch context; forgetting to exit a watch before starting another (exception in the body leaving it open is handled by __exit__, but manual misuse is not).
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
- CocoIndex timeout deadline exceeded
- async_to_sync_iter must not be called from a running event l
- LiveMap supports a single active watch() at a time.
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/538657774df7e9d5.
Report an issue: GitHub.