Desk Clarity

Everyday document & browser help

Asyncio Run Cannot Start Inside a Running Loop: Await at the Existing Boundary

By ON Lab · Sources checked November 9, 2026

Find who owns the running event loop. Inside async code, await the coroutine instead of starting another runner in the same thread. Keep one runner at a standalone script’s entry point.

Reproduce the boundary in a disposable example

A notebook or async callback raises an error when it calls asyncio.run.

import asyncio
async def calculate():
    return 21 * 2
async def host():
    pending = calculate()
    try:
        asyncio.run(pending)
    except RuntimeError:
        pending.close()  # Dispose of the coroutine rejected by run.
    else:
        raise AssertionError("expected an existing-loop error")
    assert await calculate() == 42
asyncio.run(host())
print("existing loop and direct await verified")

Read the result before changing application code

The host coroutine models an environment that already runs async code. The rejected coroutine is explicitly closed so the demonstration does not leave an unawaited-coroutine warning. That cleanup is for this controlled example, not a recipe to close a framework’s loop. In an async notebook cell, the useful operation is usually await calculate().

Choose the behavior your caller needs

Expose an async function for async callers and a separate script entry point for synchronous command-line use. Do not call run_until_complete on the same running loop as a fallback. If a synchronous callback is invoked by an async framework, follow its task scheduling and completion contract; creating a task without owning its result merely trades one problem for another. Record whether the actual caller is a notebook cell, async web handler or standalone script before choosing a fix.

Scope and limits

No third-party loop patching is required by this example. Thread-to-loop submission is a separate design and is not established by catching this RuntimeError.

Related: compare the adjacent data or execution boundary.

The embedded example was executed in an isolated local Python process on November 9, 2026. It is a reproducible boundary check, not a test of your full application.

Sources