A timeout is a deadline expiring: the operation was given a budget, the budget ran out, and the code stopped waiting. Python raises the built-in TimeoutError for OS-level waits (it is the same class socket.timeout has aliased since 3.10), and HTTP libraries raise their own Timeout types. The essential question is always which deadline fired, because a connect deadline and a read deadline indict completely different things.
import requests
requests.get("https://slow-service.example/report",
timeout=2) # server needed longer than 2s
Traceback (most recent call last):
File "main.py", line 2, in <module>
requests.exceptions.ReadTimeout:
HTTPSConnectionPool(host='slow-service.example', port=443):
Read timed out. (read timeout=2)
# ReadTimeout: the server was reached; its answer was slow
timeout=(3, 30) gives a short connect budget and a longer read budget, rather than one number silently governing both. Every network call should have some timeout; the default in requests is none, which converts server hangs into frozen programs.Timeouts that appear only at certain hours are capacity stories: the server or a shared middlebox saturates on a schedule (backups, batch jobs, peak traffic). Correlate timestamps before touching the code; the fix belongs to capacity or scheduling, not to the client.
What timeout value should I use? One derived from measurement: comfortably above the service's normal response time (its p95, if you know it) and below your callers' patience. The common failure modes are no timeout at all (hangs forever) and copying a 5-second default onto a report endpoint that legitimately needs a minute.
Is TimeoutError the same as socket.timeout? Since Python 3.10, yes: socket.timeout is an alias of the built-in TimeoutError, which itself sits under OSError. Code catching either catches both in modern Python, and the errno (110, connection timed out) appears for OS-level connect timeouts.