# asyncio.wait_for(): catching TimeoutError in Python 3.10 vs. 3.11

> Compare Python’s version-dependent timeout exceptions, choose a compatible handler, and distinguish exception-class mismatches from execution or cancellation problems.

Canonical URL: https://www.devobs.io/articles/diagnose-why-asyncio-wait-for-does-not-raise-the-built-in-timeouterror-as-0c403d3c6002bbed/
By: Lucas Vale
Published: 2026-09-11T13:33:55.561Z
Updated: 2026-09-11T13:33:55.561Z
Section: Comparisons

**For code supporting both Python 3.10 and 3.11, `except asyncio.TimeoutError:` is the compatible timeout-class handler.** Python 3.10 documents `asyncio.TimeoutError` as different from built-in `TimeoutError`. Python 3.11 documents `wait_for()` as raising built-in `TimeoutError` and makes `asyncio.TimeoutError` a deprecated alias of that class. See the versioned [3.10 timeout reference](https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for), [3.10 exception definition](https://docs.python.org/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError), [3.11 timeout reference](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.), and [3.11 alias definition](https://docs.python.org/3.11/library/asyncio-exceptions.html#asyncio.TimeoutError.).

A built-in `TimeoutError` handler failing to match is not the same as `wait_for()` raising no exception. Check the interpreter version and actual exception before deciding which problem you have.

## Compare the documented exception classes

This table compares documentation, not executed tests. Python 3.10 and 3.11 are the comparison versions; neither is an established runtime version for the issue discussed below.

| Python | Documented `wait_for()` timeout exception | Relationship to `builtins.TimeoutError` | Timeout-specific `except` clauses | Source |
|---|---|---|---|---|
| 3.10 | `asyncio.TimeoutError` | A different exception from built-in `TimeoutError` | `except asyncio.TimeoutError:` | [Tasks](https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for); [Exceptions](https://docs.python.org/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError) |
| 3.11 | Built-in `TimeoutError` | `asyncio.TimeoutError` is a deprecated alias of the built-in class | `except TimeoutError:` when unshadowed; `except builtins.TimeoutError:` after importing `builtins`; `except asyncio.TimeoutError:` through the alias | [Tasks](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.); [Exceptions](https://docs.python.org/3.11/library/asyncio-exceptions.html#asyncio.TimeoutError.) |

The 3.11 Exceptions reference explicitly dates the alias change to Python 3.11. For 3.11-specific code, the built-in spelling avoids the deprecated alias. If an import or assignment has reused the unqualified name `TimeoutError`, `builtins.TimeoutError` makes the intended class explicit.

## What the CPython issue reports

[CPython issue #110703](https://github.com/python/cpython/issues/110703), opened on October 11, 2023, is titled “asyncio.wait_for() doesn't raise builtin TimeoutError.” The title alone establishes neither the actual exception nor the cause.

The issue body provides more context. The reporter supplies code awaiting `asyncio.wait_for(asyncio.sleep(100), timeout=1)`, with an `except TimeoutError:` clause followed by `except Exception as exc:`. The reporter says the second handler receives an exception whose type is `asyncio.exceptions.TimeoutError`. That is a report of an exception missing the first handler—not of no exception being raised.

A CPython repository member suggests that the reporter is reading newer documentation while using an older interpreter, and the reporter agrees. The discussion does not identify an exact interpreter version, operating system, or event-loop implementation. It supports checking for a documentation/runtime mismatch, but it does not establish Python 3.10 as the reported environment or validate a handler change through a rerun.

## Unexecuted diagnostic: inspect the interpreter and exception

Run this as a standalone script using the interpreter that runs the affected application. **This diagnostic has not been executed here.** The broad `except Exception` is for inspection only, not a production timeout policy.

```python
import asyncio
import builtins
import sys


async def main():
    print("sys.version:", sys.version)
    print(
        "asyncio.TimeoutError is builtins.TimeoutError:",
        asyncio.TimeoutError is builtins.TimeoutError,
    )

    try:
        await asyncio.wait_for(asyncio.sleep(1), timeout=0.01)
    except Exception as exc:  # Diagnostic inspection only.
        print("Exception type:", type(exc))
        print(
            "isinstance(exc, builtins.TimeoutError):",
            isinstance(exc, builtins.TimeoutError),
        )
        print(
            "isinstance(exc, asyncio.TimeoutError):",
            isinstance(exc, asyncio.TimeoutError),
        )
    else:
        print("The awaited operation completed without an exception.")


asyncio.run(main())
```

Record observations in this empty results template. Do not substitute documentation expectations for runtime results.

| Field | Observed value |
|---|---|
| `sys.version` | |
| Exception type | |
| `isinstance(exc, builtins.TimeoutError)` | |
| `isinstance(exc, asyncio.TimeoutError)` | |
| `asyncio.TimeoutError is builtins.TimeoutError` | |

Interpret the observations as diagnostic branches:

- **Matches `asyncio.TimeoutError`, but not `builtins.TimeoutError`:** investigate an exception-class mismatch against the versioned comparison above.
- **Matches both:** the difference between those two classes does not explain a missed handler. Inspect the actual handler’s name bindings and the code path reaching it.
- **Matches neither:** investigate the exception you observed rather than relabeling it as a timeout.
- **Completes without an exception:** record that outcome and investigate execution separately; there are no exception values to fill in.

One limit matters: `asyncio.CancelledError` is a `BaseException` subclass rather than an `Exception` subclass, a change documented since Python 3.8. The diagnostic catch therefore does not intercept cancellation. The documentation says cancellation should be re-raised in almost all situations. [Source: asyncio exceptions](https://docs.python.org/3.11/library/asyncio-exceptions.html#asyncio.TimeoutError.)

## Separate handler mismatch from execution and cancellation

If no timeout exception reaches the caller, check these paths rather than assuming the handler is wrong:

- **Was the coroutine run?** Simply calling a coroutine does not schedule it. Ensure the `wait_for()` coroutine is awaited or otherwise scheduled. The diagnostic uses `asyncio.run()` to run its entry point. [Source: coroutines and tasks](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.)
- **Was there a timeout to report?** Both versions document that `timeout=None` waits until the future completes. With a finite timeout, distinguish an operation that completes before the deadline from one that times out. [Sources: Python 3.10](https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for), [Python 3.11](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.)
- **Is cancellation still in progress?** Both references say `wait_for()` cancels the task on timeout and waits until the future is actually cancelled. Total waiting time can therefore exceed the timeout. A delayed exception is not evidence that no exception will be raised. [Sources: Python 3.10](https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for), [Python 3.11](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.)
- **Did cancellation change what propagates?** Both references say an exception occurring during cancellation propagates. They also state that cancelling the wait cancels the awaited future. Investigate these cancellation paths separately from the timeout-class comparison. [Sources: Python 3.10](https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for), [Python 3.11](https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.)

These are diagnostic branches, not established explanations for the reported issue. Start with the interpreter and actual exception, choose the version-compatible timeout handler, and investigate execution or cancellation when the observations point there.

## Source references

- <https://docs.python.org/3.10/library/asyncio-task.html#asyncio.wait_for>
- <https://docs.python.org/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError>
- <https://docs.python.org/3.11/library/asyncio-task.html#asyncio.wait_for.>
- <https://docs.python.org/3.11/library/asyncio-exceptions.html#asyncio.TimeoutError.>
- <https://github.com/python/cpython/issues/110703>
