RuntimeWarning: Enable tracemalloc to get the object allocation traceback

January 16, 2024 Python Asyncio

You may get a warning when running your asyncio program that looks like: "RuntimeWarning: Enable tracemalloc to get the object allocation traceback".

This warning is caused by not awaiting a coroutine in an asyncio program and giving a suggestion on how to track down the cause. It can be fixed by awaiting the offending coroutine or suppressed by configuring the filter on the warnings module.

In this tutorial, you will discover the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" warning in asyncio programs and how to fix and suppress it.

Let's get started.

RuntimeWarning: Enable tracemalloc to get the object allocation traceback

It is common to get a RuntimeWarning warning when developing asyncio programs.

This is especially common when you are first getting started. You may see RuntimeWarning messages reported in your standard output or standard error.

A common RuntimeWarning is as follows:

RuntimeWarning: Enable tracemalloc to get the object allocation traceback

What is this RuntimeWarning all about?

What does "Enable tracemalloc" mean?

The "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" is emitted by asyncio programs.

Most commonly it is emitted when an asyncio program creates a coroutine and does not await it.

This means that the coroutine is never run in the asyncio event loop.

Creating and not running a coroutine is a common error in an asyncio program and typically raises a RuntimeWarning with the message:

RuntimeWarning: coroutine '...' was never awaited

Where '...' is replaced with the name of the coroutine that was not awaited.

You can learn more about the "RuntimeWarning: coroutine '...' was never awaited" warning in the tutorial:

Along with this warning, the following warning is emitted:

RuntimeWarning: Enable tracemalloc to get the object allocation traceback

It is emitted because the Python interpreter is giving us advice on how to track down the cause of the previous RuntimeWarning.

It is suggesting that we use the tools in the tracemalloc module to find the coroutine that was never awaited.

What is tracemalloc?

The tracemalloc module provides tools for debugging Python programs.

Specifically, provides tools for tracing memory allocation in the programs.

The tracemalloc module is a debug tool to trace memory blocks allocated by Python.

-- tracemalloc — Trace memory allocations

It is a reasonably sophisticated module and although we may use it directly, we are more likely to use it indirectly via a memory profiling tool applied to our program.

We could instrument our asyncio program with the tracemalloc module to discover the cause of the "RuntimeWarning: coroutine '...' was never awaited" warning, but this is typically not required.

How to Fix The RuntimeWarning

We can fix both RuntimeWarning warnings by awaiting the coroutine that was not awaited.

Specifically, the warnings:

When the "RuntimeWarning: coroutine '...' was never awaited" is emitted, it will report the file and line on which the coroutine was created that was never awaited.

We can go directly to this line and await the coroutine or schedule the coroutine in a way that is appropriate for our program.

For example, typically we might call a coroutine like a function, causing both RuntimeWarning warnings to be emitted:

...
# call the work coroutine
work()

This will create a coroutine object, but not run it in the event loop.

It is equivalent to the following:

...
# call the work coroutine
coro = work()

We can fix the RuntimeWarning warnings by explicitly awaiting the coroutine.

For example:

...
# await the work coroutine
await work()

You can learn more about Python coroutines in the tutorial:

We can also schedule the coroutine as an asyncio.Task via the asyncio.create_task() function.

For example:

...
# schedule the coroutine as a task
task = asyncio.create_task(work())

You can learn more about asyncio tasks in the tutorial:

And that's all there is to it.

The coroutine will be given the opportunity to run and the RuntimeWarning warnings will no longer be emitted.

How to Suppress The RuntimeWarning

It is possible that we don't care about this warning being emitted.

This could be for many reasons, such as:

As such, the RuntimeWarning may be a part of the normal operation of our program.

In this case, we can actively suppress the warning in our program.

This can be achieved by ignoring all RuntimeWarning warnings emitted by our program via the warnings module.

We can do this via the warnings.filterwarnings() function and specify the filter of 'ignore' and the category to apply it to as the RuntimeWarning.

For example:

...
# suppress RuntimeWarning
warnings.filterwarnings('ignore', category=RuntimeWarning)

This will suppress all RuntimeWarning in our asyncio program, and specifically the warnings:

Now that we know how to fix and suppress the asyncio RuntimeWarning warnings, let's look at some worked examples.

Example of RuntimeWarning: Enable tracemalloc

We can explore an example that results in the warning "RuntimeWarning: Enable tracemalloc to get the object allocation traceback".

In this example, we will define a simple coroutine that sleeps for a moment. We will then call this coroutine from the main coroutine and not await it. This will generate the RuntimeWarning indicating that the coroutine was not awaited and another RuntimeWarning to suggest to use tracemalloc to locate the cause of the fault.

Firstly, we can define a coroutine that sleeps a moment.

# task that does work
async def work():
    # block for a moment
    await asyncio.sleep(1)

We can then define the main() coroutine that reports a message, creates but does not await the work() coroutine, sleeps for 2 seconds, and reports a done message.

# main coroutine
async def main():
    # report a message
    print('Starting')
    # run the task
    work()
    # block for a moment
    await asyncio.sleep(2)
    # report a message
    print('Done')

Finally, we can start the asyncio event loop and run the main() coroutine.

...
# start the event loop
asyncio.run(main())

Tying this together the complete example is listed below.

# SuperFastPython.com
# example of a never-awaited coroutine
import asyncio

# task that does work
async def work():
    # block for a moment
    await asyncio.sleep(1)

# main coroutine
async def main():
    # report a message
    print('Starting')
    # run the task
    work()
    # block for a moment
    await asyncio.sleep(2)
    # report a message
    print('Done')

# start the event loop
asyncio.run(main())

Running the example first creates the event loop and runs the main() coroutine.

The main() coroutine runs and reports a print message, then creates but does not run the work() coroutine. It then sleeps for two seconds.

The created but unawaited work() coroutine results in two runtime warnings being generated, as we expected:

  1. RuntimeWarning: coroutine 'work' was never awaited
  2. RuntimeWarning: Enable tracemalloc to get the object allocation traceback

The main() coroutine resumes and reports a done message before the program terminates.

This highlights how we can develop a program with a coroutine that is not awaited that generates the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" warning.

Starting
...:15: RuntimeWarning: coroutine 'work' was never awaited
  work()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Done

Next, let's look at how we might fix the RuntimeWarning warnings.

Example of Fixing RuntimeWarning: Enable tracemalloc

We can explore how to fix the program so that the RuntimeWarning warnings are not emitted.

In this case, we will await the work() coroutine after it is created in the main() coroutine.

...
# run the task
await work()

And that's it.

Tying this together, the complete example is listed below.

# SuperFastPython.com
# example of fixed never-awaited coroutine
import asyncio

# task that does work
async def work():
    # block for a moment
    await asyncio.sleep(1)

# main coroutine
async def main():
    # report a message
    print('Starting')
    # run the task
    await work()
    # block for a moment
    await asyncio.sleep(2)
    # report a message
    print('Done')

# start
asyncio.run(main())

Running the example first creates the event loop and runs the main() coroutine.

The main() coroutine runs and reports a print message, then creates and awaits the work() coroutine.

The work() coroutine runs and sleeps for 1 second, before resuming and terminating.

The main() coroutine resumes and then sleeps for two seconds, then reports a final message and terminates the program.

This highlights how we can fix a program by awaiting a coroutine so that the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" warning is not emitted.

Starting
Done

Next, let's look at how we might suppress the RuntimeWarning.

Example of Suppressing RuntimeWarning: Enable tracemalloc

We can explore how we might suppress RuntimeWarning warnings so that the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" is not emitted.

In this case, we will update the first example where the work() coroutine is not awaited. Before starting the asyncio event loop, we will configure the warning system to ignore all RuntimeWarning warnings.

...
# suppress RuntimeWarning
warnings.filterwarnings('ignore', category=RuntimeWarning)

This will have the effect of suppressing both RuntimeWarning warnings emitted from the program because the coroutine is not awaited.

The complete example is listed below.

# SuperFastPython.com
# example of a never-awaited coroutine with suppressed warning
import warnings
import asyncio

# task that does work
async def work():
    # block for a moment
    await asyncio.sleep(1)

# main coroutine
async def main():
    # report a message
    print('Starting')
    # run the task
    work()
    # block for a moment
    await asyncio.sleep(2)
    # report a message
    print('Done')

# suppress RuntimeWarning
warnings.filterwarnings('ignore', category=RuntimeWarning)
# start
asyncio.run(main())

Running the example first creates the event loop and runs the main() coroutine.

The main() coroutine runs and reports a print message, then creates but does not run the work() coroutine. It then sleeps for two seconds.

The unawaited work() coroutine does cause two RuntimeWarning warnings to be generated internally within asyncio, but the configured filter on the warnings module causes them to be suppressed. Therefore their details are not reported.

The main() coroutine resumes and reports a done message before the program terminates.

This highlights how we can suppress the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" warning.

Starting
Done

Takeaways

You now know the cause, how to fix it, and how to suppress the "RuntimeWarning: Enable tracemalloc to get the object allocation traceback" warning.



If you enjoyed this tutorial, you will love my book: Python Asyncio Jump-Start. It covers everything you need to master the topic with hands-on examples and clear explanations.