title: Weird behaviour of asyncio.CancelledError and "_GatheringFuture exception was never retrieved"
body: <p>I'm watching <a href="https://youtu.be/-CzqsgaXUM8?list=PLhNSoGM2ik6SIkVGXWBwerucXjgP1rHmB&amp;t=250" rel="noreferrer">import asyncio: Learn Python's AsyncIO #3 - Using Coroutines</a>. The instructor gave the following example:</p>
  <pre><code>import asyncio
  import datetime
  
  async def keep_printing(name):
      while True:
          print(name, end=&quot; &quot;)
          print(datetime.datetime.now())
          await asyncio.sleep(0.5)
  
  async def main():
      group_task = asyncio.gather(
                       keep_printing(&quot;First&quot;),
                       keep_printing(&quot;Second&quot;),
                       keep_printing(&quot;Third&quot;)
                   )
      try:
          await asyncio.wait_for(group_task, 3)
      except asyncio.TimeoutError:
          print(&quot;Time's up!&quot;)
  
  
  if __name__ == &quot;__main__&quot;:
      asyncio.run(main())
  </code></pre>
  <p>The output had an exception:</p>
  <pre><code>First 2020-08-11 14:53:12.079830
  Second 2020-08-11 14:53:12.079830
  Third 2020-08-11 14:53:12.080828 
  First 2020-08-11 14:53:12.580865
  Second 2020-08-11 14:53:12.580865
  Third 2020-08-11 14:53:12.581901 
  First 2020-08-11 14:53:13.081979
  Second 2020-08-11 14:53:13.082408
  Third 2020-08-11 14:53:13.082408 
  First 2020-08-11 14:53:13.583497
  Second 2020-08-11 14:53:13.583935
  Third 2020-08-11 14:53:13.584946
  First 2020-08-11 14:53:14.079666
  Second 2020-08-11 14:53:14.081169
  Third 2020-08-11 14:53:14.115689
  First 2020-08-11 14:53:14.570694
  Second 2020-08-11 14:53:14.571668
  Third 2020-08-11 14:53:14.635769
  First 2020-08-11 14:53:15.074124
  Second 2020-08-11 14:53:15.074900
  Time's up!
  _GatheringFuture exception was never retrieved
  future: &lt;_GatheringFuture finished exception=CancelledError()&gt;
  concurrent.futures._base.CancelledError
  </code></pre>
  <p>The instructor tried to the handle the <code>CancelledError</code> by adding a <code>try/except</code> in <code>keep_printing</code>:</p>
  <pre><code>async def keep_printing(name):
      while True:
          print(name, end=&quot; &quot;)
          print(datetime.datetime.now())
          try:
              await asyncio.sleep(0.5)
          except asyncio.CancelledError:
              print(name, &quot;was cancelled!&quot;)
              break
  </code></pre>
  <p>However, the same exception still occurred:</p>
  <pre><code># keep printing datetimes
  ...
  First was cancelled!
  Second was cancelled!
  Third was cancelled!
  Time's up!
  _GatheringFuture exception was never retrieved
  future: &lt;_GatheringFuture finished exception=CancelledError()&gt;
  concurrent.futures._base.CancelledError
  </code></pre>
  <p>The instructor then just proceeded to other topics and never came back to this example to show how to fix it. Fortunately, through experimentation, I discovered that we could fix it by adding another <code>try/except</code> under the <code>except asyncio.TimeoutError:</code> in the <code>main</code> async function:</p>
  <pre><code>async def main():
      group_task = asyncio.gather(
                       keep_printing(&quot;First&quot;),
                       keep_printing(&quot;Second&quot;),
                       keep_printing(&quot;Third&quot;)
                   )
      try:
          await asyncio.wait_for(group_task, 3)
      except asyncio.TimeoutError:
          print(&quot;Time's up!&quot;)
          try:
              await group_task
          except asyncio.CancelledError:
              print(&quot;Main was cancelled!&quot;)
  </code></pre>
  <p>The final output was:</p>
  <pre><code># keep printing datetimes
  ...
  First was cancelled!
  Second was cancelled!
  Third was cancelled!
  Time's up!
  Main was cancelled!
  </code></pre>
  <p>In fact, with this edition of <code>main</code>, we don't even need the <code>try...except asyncio.CancelledError</code> in <code>keep_printing</code>. It would still work fine.</p>
  <p>Why was that? Why did catching <code>CancelledError</code> in <code>main</code> work but not in <code>keep_printing</code>? The way that the video instructor dealt with this exception only made me more confused. He didn't need to change any code of <code>keep_printing</code> in the first place!</p>