"coroutine was never awaited": the async function you called without await, and where to find them all
verbatim errorRuntimeWarning: coroutine 'Database.save_event' was never awaited
coroutine: Database.save_event() -> None
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Problem
An event-tracking side effect in a FastAPI service silently stopped working:
RuntimeWarning: coroutine 'Database.save_event' was never awaited
coroutine: Database.save_event() -> None
RuntimeWarning: Enable tracemalloc to get the object allocation tracebackNo exception. The request returned 200. The event was just... not saved. The warning scrolled past in logs nobody read.
Root cause
Calling an async def function returns a coroutine object — it does not run anything. Without await, the coroutine is created and immediately garbage-collected, producing the warning and executing zero of its body. Ours:
def log_event(event): # sync helper, called from an async handler
db.save_event(event) # async def — this line created, then dropped, a coroutineThe extra trap: this bug is invisible in tests if the test suite's event loop collects pending coroutines or the DB layer uses a mock that swallows the call. It surfaced only because production counts disagreed with our dashboards.
fix preview — first 1 of 2 lines (python), truncated:
async def log_event(event):
… 1 more line in the fix🔒 the fix — including 4 code blocks — is members-only. $1/mo unlocks everything.