Encountering the RuntimeWarning: Enable tracemalloc to get the object allocation traceback in asyncio code can be confusing. While the warning suggests using the tracemalloc module, the underlying issue is almost always a different RuntimeWarning: coroutine '...' was never awaited.
This guide explains why these warnings appear together and how to fix the root cause – the missing await.
Understanding the Warnings: Unawaited Coroutines
In Python's asyncio, when you call an async def function or certain asyncio library functions (like asyncio.sleep), they return a coroutine object. This object represents the asynchronous operation but doesn't execute it immediately.
To run the coroutine and get its result (or wait for it to finish), you must use the await keyword from within another async function.
If you call a coroutine function but forget to await it:
- A coroutine object is created but never scheduled or run by the event loop.
- Python's garbage collector eventually finds this unreferenced, unrun coroutine object.
- This triggers the
RuntimeWarning: coroutine '...' was never awaited. - As a secondary effect, because an object (the coroutine) was created but potentially seems unused or improperly handled, Python also often suggests enabling
tracemalloc(RuntimeWarning: Enable tracemalloc...).tracemallocis a debugging tool to trace memory allocations, which could help find where the unawaited coroutine object was created if the location wasn't obvious.
Key Point: The tracemalloc warning is a symptom. The actual problem you need to fix is the missing await.
Illustrative Error Example
This code demonstrates the warning caused by forgetting await before asyncio.sleep():
import asyncio
async def my_coroutine():
print('tutorial')
asyncio.sleep(0.5) # <--- Forgot 'await' here!
print('reference.com')
async def main():
task = asyncio.create_task(my_coroutine())
await task # Wait for the task wrapping my_coroutine
asyncio.run(main())The Solution: Add the await Keyword
The fix is straightforward: add the await keyword before any call that returns a coroutine object you intend to run.
import asyncio
async def my_coroutine():
print('tutorial')
await asyncio.sleep(0.5) # Added 'await'
print('reference.com')
async def main():
task = asyncio.create_task(my_coroutine())
await task
asyncio.run(main())Output:
tutorial
(pauses for ~0.5 seconds)
reference.com- By adding
awaitbeforeasyncio.sleep(0.5), we correctly pausemy_coroutineand allow the event loop to run the sleep operation. The warnings disappear.
Common Scenarios for Missing await
Ensure you await in these situations:
Awaiting asyncio Functions
Many built-in asyncio functions return coroutines and must be awaited:
asyncio.sleep()asyncio.wait()asyncio.gather()asyncio.open_connection()- Methods on streams like
stream.read(),stream.write() - And many others...
Awaiting Custom async def Functions
Any function you define using async def returns a coroutine object when called and must be awaited from within another async function.
import asyncio
async def greet(name):
print(f"(Running greet for {name})")
await asyncio.sleep(0.1) # Simulate work
return f'hello {name}'
async def main():
result_coro = greet('tom nolan') # Forgot await! result_coro is a coroutine object
print(f"Result type: {type(result_coro)}") # Will show <class 'coroutine'>
asyncio.run(main())
import asyncio
async def greet(name):
print(f"(Running greet for {name})")
await asyncio.sleep(0.1)
return f'hello {name}'
async def main():
result_str = await greet('tom nolan')
print(result_str) # Output: hello tom nolan
asyncio.run(main())What About tracemalloc?
tracemalloc is a powerful standard library module for debugging memory usage and tracking where objects are allocated.
While Python suggests it when an unawaited coroutine is detected (because an "unused" object was created), enabling tracemalloc will not fix the underlying missing await problem.
It's merely a hint that might help you locate the source of the unawaited coroutine if it's deeply nested or hard to find. Focus on finding and adding the missing await.
Calling Async Functions from Synchronous Code
You can not use await directly in regular synchronous functions. To run an async function from synchronous code, use asyncio.run():
import asyncio
async def greet(name):
await asyncio.sleep(0.1)
return f'hello {name}'
if __name__ == "__main__":
message = asyncio.run(greet('tom nolan'))
print(message) # Output: hello tom nolanConclusion
The RuntimeWarning: Enable tracemalloc... in asyncio is almost always a secondary warning triggered by the primary issue: a forgotten await keyword.
- Focus on identifying where you called an
asyncfunction or an awaitableasynciofunction without preceding it withawait. - Correcting this will resolve both warnings and ensure your asynchronous code executes correctly.