Missing Await on Coroutine
ID |
python.missing_await_coroutine |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Python |
Tags |
reliability, suspicious-call |
Description
Reports a call to an async def function whose returned coroutine is consumed without await. The call returns a coroutine object, not the resolved value, so the caller almost always gets a surprising result and Python emits RuntimeWarning: coroutine 'foo' was never awaited when the coroutine is garbage-collected.
async def fetch(url):
return url
async def caller():
fetch("/x") # FLAW — coroutine never awaited
value = fetch("/y") # FLAW — value is a coroutine object, not the resolved value
await fetch("/z") # OK
The rule resolves the callee via the local symbol table — only bare-name calls to in-module async def functions are detected. Calls intentionally scheduled via asyncio.create_task / ensure_future are out of scope (they return a Task, not a coroutine).
Rationale
A dangling coroutine almost never does what the writer intended: comparisons fail, str() returns <coroutine object …>, and the underlying I/O never runs.
Remediation
-
Add
awaitif you want the resolved value. -
Use
asyncio.create_task(…)if you want the call to run concurrently and you’ll await it later. -
If you’re inside a sync function, call from an event loop (
asyncio.run(…)) — synchronous code cannot await directly.