{"record":{"id":"538657774df7e9d5","repo":"cocoindex-io/cocoindex","slug":"self-label-supports-a-single-active-watch-at","errorCode":null,"errorMessage":"{self._label} supports a single active watch() at a time.","messagePattern":"(.+?) supports a single active watch\\(\\) at a time\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectorkits/__init__.py","lineNumber":50,"sourceCode":"\n    The flag resets on every exit — normal return, exception, or cancellation (a\n    cancelled ``await`` inside the ``with`` unwinds through ``__exit__``) — so the\n    feed can be re-watched sequentially after a prior ``watch()`` finishes.\n\n    A plain flag (no lock) suffices when ``watch()`` runs entirely on one event\n    loop, as the framework's live consumer does. A feed that already carries\n    equivalent \"is being watched\" state can guard on that instead.\n    \"\"\"\n\n    __slots__ = (\"_label\", \"_active\")\n\n    def __init__(self, label: str) -> None:\n        self._label = label\n        self._active = False\n\n    def __enter__(self) -> None:\n        if self._active:\n            raise RuntimeError(\n                f\"{self._label} supports a single active watch() at a time.\"\n            )\n        self._active = True\n\n    def __exit__(self, *exc: object) -> None:\n        self._active = False\n\n\ndef default_subpath_name(processor_fn: Any) -> str | None:\n    \"\"\"Resolve the default subpath name for a mount target.\n\n    Honors an explicit ``__coco_subpath_name__`` attribute (set by wrappers\n    like ``coco.auto_refresh`` so the wrapper class can keep an honest\n    ``__name__`` while still mounting under the wrapped function's name),\n    falling back to ``__name__``.\n    \"\"\"\n    name = getattr(processor_fn, \"__coco_subpath_name__\", None)\n    if isinstance(name, str):","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectorkits/__init__.py#L32-L68","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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)"],"exampleFix":"// before\nw1 = res.watch(); w2 = res.watch()\nwith w1, w2:  # RuntimeError\n// after\nwith res.watch():\n    handle_events()","handlingStrategy":"try-catch","validationCode":"if watch_handle._active:\n    raise RuntimeError(\"watch already active; exit it before re-entering\")","typeGuard":null,"tryCatchPattern":"try:\n    with resource.watch():\n        consume()\nexcept RuntimeError as e:\n    if \"single active watch\" in str(e):\n        serialize_watch_usage()  # retry sequentially","preventionTips":["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"],"tags":["concurrency","watch","resource-lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}