#529·tenacity

retry_if_not_exception_type swallows asyncio.CancelledError

Author: jackwildmanCreated Jun 24, 2025Updated Jun 24, 2025

Problem

When using retry_if_no_exception_type to avoid retries for a specific exception, this causes asyncio.CancelledError to be caught and retried. This is contra-typical behaviour, as CancelledError does not typically cause a retry to occur in other scenarios. This is because task cancellation is not typically a retry case, and allow these errors to bubble up enables cancellation utilities like asyncio.wait_for to work as excpected.

Steps to reproduce

Observe the behaviour as expected with this:

from tenacity import retry, wait_fixed, stop_after_attempt
import asyncio

@retry(
    wait=wait_fixed(10),
    stop=stop_after_attempt(2),
    reraise=True,
)
async def test():
    print("Sleeping")
    await asyncio.sleep(3)
    print("Done")

await asyncio.wait_for(test(), 1)  # Expected to cancel after 1s

The output here is:

Sleeping
CancelledError                            Traceback (most recent call last)
... (traceback)

We see incorrect behaviour in this case:

from tenacity import retry, wait_fixed, stop_after_attempt, retry_if_not_exception_type
import asyncio

@retry(
    wait=wait_fixed(10),
    stop=stop_after_attempt(2),
    reraise=True,
    retry=retry_if_not_exception_type(ValueError)
)
async def test_with_issue():
    print("Sleeping")
    await asyncio.sleep(3)
    print("Done")

await asyncio.wait_for(test_with_issue(), 1)  # Expected to cancel after 1s

The output here is:

Sleeping
Sleeping
Done

Here we see the retry occurring. We expect no retry to occur, and for the behaviour in this case to be the same as the former.