{"record":{"id":"3136fa72bece66d3","repo":"cocoindex-io/cocoindex","slug":"async-to-sync-iter-must-not-be-called-from-a-runni","errorCode":null,"errorMessage":"async_to_sync_iter must not be called from a running event loop","messagePattern":"async_to_sync_iter must not be called from a running event loop","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectorkits/async_adapters.py","lineNumber":139,"sourceCode":"\n    Raises:\n        RuntimeError: If called from within a running event loop.\n        Any exception raised by the async iterator is re-raised.\n\n    Example:\n        >>> async def async_generator(start: int, end: int):\n        ...     for i in range(start, end):\n        ...         yield i\n        ...\n        >>> for value in async_to_sync_iter(lambda: async_generator(0, 5)):\n        ...     print(value)\n    \"\"\"\n    try:\n        _asyncio.get_running_loop()\n    except RuntimeError:\n        pass  # No running loop, which is what we want\n    else:\n        raise RuntimeError(\n            \"async_to_sync_iter must not be called from a running event loop\"\n        )\n\n    q: _queue.Queue[tuple[bool, _T | Exception]] = _queue.Queue(maxsize=max_queue_size)\n    stop_event = _threading.Event()\n\n    def producer() -> None:\n        async def run_async() -> None:\n            try:\n                async for item in async_iter_fn():\n                    if stop_event.is_set():\n                        break\n                    q.put((False, item))\n            except Exception as e:  # pylint: disable=broad-except\n                q.put((True, e))\n            finally:\n                q.put((True, StopIteration()))\n","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectorkits/async_adapters.py#L121-L157","documentation":"async_to_sync_iter bridges an async iterator into a synchronous one using a background thread, which must own the event loop; calling it from inside a running event loop would deadlock (the sync iteration would block the loop the async side needs). It therefore raises this RuntimeError eagerly.","triggerScenarios":"Calling async_to_sync_iter(...) (directly or via __iter__ of the adapter) inside an async def function or any code running on an active asyncio loop — e.g. `for x in async_to_sync_iter(aiter())` inside async code.","commonSituations":"Using the sync adapter inside a Jupyter notebook or FastAPI handler (both run a loop); wrapping an async iterator in sync code that was itself made async; mixing asyncio.run with an outer loop.","solutions":["Move the sync iteration out of async code — call it from a plain sync function or a separate thread","Inside async code, iterate the async iterator directly with `async for`","If a sync API requires the data, materialize it first with asyncio.run() in a thread outside the loop (or run_in_executor)","For scripts, ensure no outer event loop is running when using the sync adapter"],"exampleFix":"// before\nasync def main():\n    for item in async_to_sync_iter(agen()):  # RuntimeError\n        ...\n// after\nasync def main():\n    async for item in agen():\n        ...","handlingStrategy":"validation","validationCode":"import asyncio\nif asyncio.get_event_loop().is_running():\n    raise RuntimeError(\"use async iteration inside async code\")","typeGuard":"def can_use_sync_iter() -> bool:\n    try:\n        asyncio.get_running_loop()\n        return False\n    except RuntimeError:\n        return True","tryCatchPattern":"try:\n    for item in async_to_sync_iter(aiter):\n        process(item)\nexcept RuntimeError as e:\n    if \"running event loop\" in str(e):\n        run_in_thread(lambda: consume_sync(aiter))","preventionTips":["Only use sync adapters from threads without a running event loop","Inside async code use `async for` directly","In Jupyter/FastAPI, run sync adapters via run_in_executor or a worker thread"],"tags":["asyncio","concurrency","iterators"],"backgroundTag":"unsupported-operation","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}