InvalidStateError: Result is not set
You can get an InvalidStateError exception when attempting to retrieve a return value result from an asyncio Task.
This will happen if we retrieve a result via the result() method on a task while the task is still running, e.g. the task is not yet done.
We can avoid the InvalidStateError exception by waiting for the task to be done before attempting to retrieve the result either directly or via a function such as asyncio.gather() or asyncio.wait().
In this tutorial, you will discover why we get the InvalidStateError: "Result is not set" and how to fix it.
Let's get started.
InvalidStateError: Result is not set
It is common to get an InvalidStateError exception when using asyncio.
An InvalidStateError exception is raised with the message:
- InvalidStateError: Result is not set
Developers often get this exception when first getting started with asyncio.
What does this InvalidStateError exception mean?
How can we fix it and avoid it in the future?
Why Do We Get An InvalidStateError
We get an InvalidStateError exception when we try to retrieve a return value result from an asyncio.Task while the task is still running.
This will happen if we call the result() method on an asyncio.Task() instance and the task is not done.
For example:
...
# attempt to get a result from the task
value = task.result()
This is the regular way to get a return value result from a task.
It will return the return value from the Task's coroutine or re-raise an exception if the coroutine failed with an uncancelled exception.
The problem is, we must wait until the task is completed, e.g, has the state "done". This means that the done() method on the task returns True.
You can learn more about retrieving results from tasks in the tutorial:
How to Avoid InvalidStateError
We can avoid an InvalidStateError when calling the result() method by waiting for the task to be done.
There are many ways we can do this, such as:
- Await the task directly
- Await the task via asyncio.gather()
- Await the task via asyncio.wait()
Let's take a closer look at each in turn.
Await The Task Directly
The first approach is to await the task directly.
For example:
...
# wait for the task to be done and get the result
result = await task
This does two things:
- Waits for the task to be done.
- Retrieves the return value from the task.
We would no longer need to call the result() method on the task. Nevertheless, we can call the result() method if we prefer.
For example:
...
# wait for the task to be done
await task
# attempt to get a result from the task
value = task.result()
You can learn more about awaiting in the tutorial:
Await The Task Via asyncio.gather()
Another approach is to use the asyncio.gather() function.
This function takes one or more awaitables and returns once they are all done.
For example:
...
# wait for the task to be done
_ = await asyncio.gather(task)
# attempt to get a result from the task
value = task.result()
The asyncio.gather() function itself will return a list of return values, so we may want to retrieve the return value from it directly.
For example:
...
# wait for the task to be done
results = await asyncio.gather(task)
# get the result
value = results[0]
You can learn more about how to use the asyncio.gather() function in the tutorial:
Await The Task Via asyncio.wait()
Another similar approach is to use the asyncio.wait() function.
This function takes a collection of tasks and returns once a condition is met, where the default condition is that all provided tasks are done.
This means that we will have to enclose our single task in a list.
For example:
...
# wait for the task to be done
_ = await asyncio.wait()
# attempt to get a result from the task
value = task.result()
You can learn more about the asyncio.wait() function in the tutorial:
Now that we know how to avoid the InvalidStateError, let's look at some worked examples
Example of InvalidStateError: Result is not set
We can explore an example that raises an InvalidStateError.
In this case, we can define a custom coroutine that does some work and then returns a value. Our main program will schedule the coroutine as a background task, sleep a moment then attempt to retrieve and report the task result, which will fail with an InvalidStateError exception.
Firstly, we can define a custom coroutine that reports a message, sleeps for one second, and then returns a value.
The work() coroutine below implements this.
# custom coroutine
async def work():
# report a message
print('work() is working!')
# sleep a moment to simulate work
await asyncio.sleep(1)
# return the result
return 100
Next, we can define the main() coroutine.
A message is printed, then a work() coroutine is created and scheduled as a background task. The main() coroutine then sleeps for half a second, not long enough for the task to be completed.
It then retrieves and reports the result from the task before printing a final message.
The main() coroutine below implements this.
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait a moment
await asyncio.sleep(0.5)
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
Finally, we can start the event loop.
...
# start the event loop
asyncio.run(main())
Tying this together, the complete example is listed below.
# SuperFastPython.com
# example of InvalidStateError: Result is not set
import asyncio
# custom coroutine
async def work():
# report a message
print('work() is working!')
# sleep a moment to simulate work
await asyncio.sleep(1)
# return the result
return 100
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait a moment
await asyncio.sleep(0.5)
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
# start the event loop
asyncio.run(main())
Running the example first starts the asyncio event loop and runs the main() coroutine.
The main() coroutine runs and reports a message.
It then creates the work() coroutine and schedules it as a background task. It then suspends and sleeps for half a second.
The work() task runs and reports a message before suspending and sleeping for one second.
The main() coroutine resumes and attempts to retrieve the result from the task.
This fails with an InvalidStateError exception and the message "Result is not set".
This highlights that if we attempt to retrieve a result via the result() method before the task is done an InvalidStateError exception will be raised.
Main is running
work() is working!
Traceback (most recent call last):
File "...", line 28, in <module>
asyncio.run(main())
File ".../asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File ".../asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../asyncio/base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "...", line 23, in main
print(f'Got: {task.result()}')
^^^^^^^^^^^^^
asyncio.exceptions.InvalidStateError: Result is not set.
Example of Avoiding InvalidStateError By Awaiting
We can explore how to avoid the InvalidStateError exception by awaiting the target task directly.
In this case, we can update the above example to await the task, and then retrieve the return value.
...
# wait for the task to be done
await task
# report the result
print(f'Got: {task.result()}')
The updated main() coroutine with this change is listed below.
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
await task
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
Tying this together, the complete example is listed below.
# SuperFastPython.com
# example of avoiding InvalidStateError by awaiting
import asyncio
# custom coroutine
async def work():
# report a message
print('work() is working!')
# sleep a moment to simulate work
await asyncio.sleep(1)
# return the result
return 100
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
await task
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
# start the event loop
asyncio.run(main())
Running the example first starts the asyncio event loop and runs the main() coroutine.
The main() coroutine runs and reports a message.
It then creates the work() coroutine and schedules it as a background task. It then suspends and awaits the task directly.
The work() task runs and reports a message before suspending and sleeping for one second.
The work() task then resumes and returns a value, terminating the task.
The main() coroutine resumes and retrieves the return value from the task and reports it before reporting a final message.
This highlights how we can avoid an InvalidStateError exception by awaiting the task directly.
Main is running
work() is working!
Got: 100
Main is done
Example of Avoiding InvalidStateError By asyncio.gather()
We can explore how to avoid an InvalidStateError exception by awaiting the task with asyncio.gather().
In this case, we can update the example by awaiting a call to asyncio.gather() and passing the task instance as an argument.
...
# wait for the task to be done
await asyncio.gather(task)
The updated main() coroutine with this change is listed below.
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
await asyncio.gather(task)
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
Tying this together, the complete example is listed below.
# SuperFastPython.com
# example of avoiding InvalidStateError by asyncio.gather()
import asyncio
# custom coroutine
async def work():
# report a message
print('work() is working!')
# sleep a moment to simulate work
await asyncio.sleep(1)
# return the result
return 100
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
await asyncio.gather(task)
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
# start the event loop
asyncio.run(main())
Running the example first starts the asyncio event loop and runs the main() coroutine.
The main() coroutine runs and reports a message.
It then creates the work() coroutine and schedules it as a background task.
It then suspends and awaits the task in a call to asyncio.gather().
The work() task runs and reports a message before suspending and sleeping for one second.
The work() task then resumes and returns a value, terminating the task.
The main() coroutine resumes and retrieves and reports the return value from the task.
This highlights how we can avoid an InvalidStateError exception by awaiting the task with asyncio.gather().
Main is running
work() is working!
Got: 100
Main is done
Example of Avoiding InvalidStateError By asyncio.wait()
We can explore how to avoid an InvalidStateError exception by awaiting the task with asyncio.wait().
In this case, we can update the example by awaiting a call to asyncio.wait() and passing the task instance as an argument wrapped in a new list object.
...
# wait for the task to be done
_ = await asyncio.wait()
The updated main() coroutine with this change is listed below.
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
_ = await asyncio.wait()
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
Tying this together, the complete example is listed below.
# SuperFastPython.com
# example of avoiding InvalidStateError by asyncio.wait()
import asyncio
# custom coroutine
async def work():
# report a message
print('work() is working!')
# sleep a moment to simulate work
await asyncio.sleep(1)
# return the result
return 100
# main coroutine
async def main():
# entry point of the program
print('Main is running')
# schedule as task
task = asyncio.create_task(work())
# wait for the task to be done
_ = await asyncio.wait()
# report the result
print(f'Got: {task.result()}')
# report final message
print('Main is done')
# start the event loop
asyncio.run(main())
Running the example first starts the asyncio event loop and runs the main() coroutine.
The main() coroutine runs and reports a message.
It then creates the work() coroutine and schedules it as a background task.
It then suspends and awaits the task in a call to asyncio.wait() as a one-item list.
The work() task runs and reports a message before suspending and sleeping for one second.
The work() task then resumes and returns a value, terminating the task.
The main() coroutine resumes and retrieves and reports the return value from the task.
This highlights how we can avoid an InvalidStateError exception by awaiting the task within asyncio.wait().
Main is running
work() is working!
Got: 100
Main is done
Takeaways
You now know why we get the InvalidStateError: "Result is not set" and how to fix it.