Client timeouts and exceptions

aiohttp · Practical · 11 min

The default 5-minute total timeout is too long for most services, and errors need distinct handling.

aiohttp's timeouts are set with aiohttp.ClientTimeout, on the session or per request (timeout=). The fields:

  • total: the whole operation including connection, sending and reading the body. Default 300 seconds.
  • connect: acquiring a connection, including waiting for a free one in the pool.
  • sock_connect: establishing a new TCP connection (default 30 seconds).
  • sock_read: maximum gap between pieces of data read from the socket.

A total timeout raises asyncio.TimeoutError (the built-in TimeoutError on Python 3.11+). Socket-level timeouts raise aiohttp.ConnectionTimeoutError or aiohttp.SocketTimeoutError, which are also subclasses of TimeoutError, so except TimeoutError catches all of them.

The exception hierarchy under aiohttp.ClientError:

  • ClientResponseError (from raise_for_status, with .status), plus ContentTypeError,
  • ClientConnectionError with ClientConnectorError (DNS failure, connection refused), ServerDisconnectedError, ClientOSError and SSL errors such as ClientConnectorCertificateError,
  • InvalidURL, ClientPayloadError (body was truncated or malformed).

A robust fetch catches TimeoutError and aiohttp.ClientError, logs, and retries only when safe. Retries are not built in; write a small loop with backoff or use a package such as aiohttp-retry or tenacity.

Set a sensible session-wide timeout, e.g. ClientTimeout(total=30, sock_connect=5), and override it for known slow endpoints.

Example

import asyncio
import aiohttp

async def fetch(session, path):
    try:
        async with session.get(path) as resp:
            resp.raise_for_status()
            return f"ok {resp.status}"
    except TimeoutError:
        return "timed out"
    except aiohttp.ClientResponseError as e:
        return f"HTTP {e.status}"
    except aiohttp.ClientConnectionError as e:
        return f"connection problem: {type(e).__name__}"

async def main():
    timeout = aiohttp.ClientTimeout(total=2, sock_connect=1)
    async with aiohttp.ClientSession("https://httpbin.org", timeout=timeout) as s:
        print(await fetch(s, "/get"))          # ok 200
        print(await fetch(s, "/delay/5"))      # timed out
        print(await fetch(s, "/status/503"))   # HTTP 503
    async with aiohttp.ClientSession(timeout=timeout) as s:
        print(await fetch(s, "http://localhost:1/"))  # connection problem: ClientConnectorError

asyncio.run(main())

Remember

  • ClientTimeout(total, connect, sock_connect, sock_read); default total is 300 s
  • Timeouts raise TimeoutError subclasses; other failures are aiohttp.ClientError
  • Retries are not built in

Watch out for

  • Relying on the 5-minute default total timeout in a latency-sensitive service.

Check yourself

  1. Which exception should you catch to handle every kind of aiohttp timeout?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.aiohttp.org/en/stable/client_quickstart.html#timeouts