cocoindex-io/cocoindex · error · RuntimeError

Cannot use sync 'with coco.runtime()' from within an async e

Error message

Cannot use sync 'with coco.runtime()' from within an async event loop. Use 'async with coco.runtime()' instead.

What it means

coco.runtime() supports both sync and async context-manager forms. The sync __enter__ calls start_blocking(), which cannot run inside a running asyncio event loop (it blocks the loop), so it detects a running loop and raises immediately with the correct alternative.

Source

Thrown at python/cocoindex/_internal/api.py:709

    """Stop the default environment synchronously (and exit its lifespan, if any)."""
    environment.stop_sync()


async def default_env() -> environment.Environment:
    """Get the default environment (starting it if needed)."""
    return await environment.start()


class _DualModeRuntime:
    """Context manager that works with both `with` and `async with`."""

    def __enter__(self) -> None:
        try:
            asyncio.get_running_loop()
        except RuntimeError:
            pass  # No running loop — sync usage is fine
        else:
            raise RuntimeError(
                "Cannot use sync 'with coco.runtime()' from within an async event loop. "
                "Use 'async with coco.runtime()' instead."
            )
        start_blocking()
        return None

    def __exit__(self, *exc: Any) -> None:
        stop_blocking()

    async def __aenter__(self) -> None:
        await start()
        return None

    async def __aexit__(self, *exc: Any) -> None:
        await stop()


def runtime() -> _DualModeRuntime:

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Use `async with coco.runtime():` instead of `with coco.runtime():`
  2. In notebooks, use the async form (or nest_asyncio only as a last resort)
  3. Move the sync usage to plain non-async script code where no loop is running

Example fix

// before
with coco.runtime():
    app.update_blocking()
// after
async with coco.runtime():
    await app.update()
Defensive patterns

Strategy: type-guard

Validate before calling

import asyncio
if asyncio.get_running_loop() is not None:  # inside running loop
    ...  # use async form
# usage
if _in_loop():
    async with coco.runtime():
        ...
else:
    with coco.runtime():
        ...

Type guard

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

Try / catch

try:
    with coco.runtime():
        ...
except RuntimeError as e:
    if "async event loop" in str(e):
        raise  # switch call site to `async with coco.runtime()`

Prevention

When it happens

Trigger: Using `with coco.runtime():` inside an async def function or any code running on an asyncio event loop (e.g. inside a Jupyter notebook with an active loop, or an async app).

Common situations: Jupyter/IPython notebooks where a loop is always running; calling sync-style runtime setup inside async test code; copy-pasting sync examples into async apps.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/ccf07ec0b676014a. Report an issue: GitHub.