docling-project/docling · error · RuntimeError

This method cannot run inside an active asyncio loop. Call i

Error message

This method cannot run inside an active asyncio loop. Call it from synchronous code.

What it means

RuntimeError raised by _ensure_sync_bridge_allowed when a synchronous API (e.g. sync convert_all iteration or other sync wrappers that bridge async generators via a private event loop) is called from inside a running asyncio loop. Bridging would deadlock the loop, so the client refuses.

Source

Thrown at docling/service_client/client.py:2077

            # Drive the fan-out through the native async client so the sync batch
            # API runs concurrently on a private event loop without threads.
            async with self._build_async_service_client() as async_client:
                async for outcome in async_client.submit_and_retrieve_each(
                    items=item_list,
                    max_in_flight=max_in_flight,
                    ordered=ordered,
                    target=target,
                ):
                    yield outcome

        return self._iterate_async_generator_sync(run())

    def _ensure_sync_bridge_allowed(self) -> None:
        try:
            asyncio.get_running_loop()
        except RuntimeError:
            return
        raise RuntimeError(
            "This method cannot run inside an active asyncio loop. "
            "Call it from synchronous code."
        )

    def _iterate_async_generator_sync(
        self, async_iterator: AsyncGenerator[_T, None]
    ) -> Iterator[_T]:
        loop = asyncio.new_event_loop()

        def iterator() -> Iterator[_T]:
            try:
                asyncio.set_event_loop(loop)
                while True:
                    try:
                        yield loop.run_until_complete(anext(async_iterator))
                    except StopAsyncIteration:
                        break
            finally:

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Use the async API instead: await client.async_convert(...) / the async equivalents inside async code
  2. In scripts, keep sync calls in plain functions with no running loop
  3. In Jupyter, run sync calls in a separate thread or switch to the async client

Example fix

# before
async def handle():
    for res in client.convert_all(sources):  # RuntimeError
        ...

# after
async def handle():
    async for res in client.async_convert_all(sources):
        ...
Defensive patterns

Strategy: type-guard

Validate before calling

import asyncio

def in_async_context() -> bool:
    try:
        asyncio.get_running_loop()
        return True
    except RuntimeError:
        return False

# assert not in_async_context() before calling sync client methods

Type guard

def in_async_context() -> bool:
    try:
        asyncio.get_running_loop()
        return True
    except RuntimeError:
        return False

Try / catch

try:
    sync_call()
except RuntimeError as exc:
    if 'cannot run inside an active asyncio loop' in str(exc):
        switch_to_async_api()

Prevention

When it happens

Trigger: Calling the sync iteration path (methods that call _iterate_async_generator_sync) from inside 'async def' code or a Jupyter cell, where asyncio.get_running_loop() succeeds.

Common situations: Using sync client methods inside Jupyter notebooks (which run a loop), FastAPI handlers, or any async framework; mixing sync/async client styles in one codebase.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/694e09c225e23c20. Report an issue: GitHub.