5. Always use a timeout

You might have noticed timeout=5 in the previous example. That small argument isn't a nice-to-have; it's essential.

Without a timeout, your program is willing to wait forever if a server never responds. "Forever" is literal: that line of code sits there blocked until you manually stop the script or restart the process. By adding timeout=10, you're telling requests: "Wait up to 10 seconds for this server to respond, then give up and raise an error."

  • Without a timeout: your program can hang indefinitely.
  • With a timeout: your program fails fast, and you can handle the exception.
The silent failure mode

A request without a timeout doesn't raise an error when the server stops responding. It just sits there. No exception, no log line, no progress bar, nothing. The script looks like it's still running because it is: it's blocked on a socket read that will never complete. Newcomers hit this and assume the API is "slow"; the real cause is that they never told requests when to give up.

A request that completes in time

First, a happy-path request. Save this as with_timeout.py:

with_timeout.py
import requests

response = requests.get("https://httpbin.org/get", timeout=10)
print("Request completed successfully!")
print(f"Status code: {response.status_code}")
print(f"Response type: {type(response)}")

Run it from the project root:

Terminal
$ python with_timeout.py
Request completed successfully!
Status code: 200
Response type: <class 'requests.models.Response'>

The timeout=10 tells requests to wait at most 10 seconds for the server to respond. If it's slower, requests raises a Timeout exception instead of leaving your program stuck. That small safeguard makes a big difference in real-world reliability.

Timeouts protect your application from hanging, but they also remind you that network calls live in the real world, not in a perfectly reliable lab:

  • Local networks. Usually fast (milliseconds); timeouts are rarely triggered.
  • Internet services. Performance varies (50 to 500 ms is typical); occasional delays are normal.
  • Overloaded servers. May respond slowly or not at all during high traffic.
  • Network congestion. Can introduce delays anywhere along the route.

Seeing a timeout error in action

Now we'll deliberately trigger a timeout so you know what it looks like when it happens for real. httpbin has a /delay/N endpoint that waits up to N seconds before responding, capped at 10 seconds, which is perfect for testing. We'll ask the server to wait 10 seconds but only give it 5 before we give up.

Replace the contents of with_timeout.py with this:

with_timeout.py (forcing a timeout)
import requests

# This server will delay for 10 seconds, but we'll only wait 5
response = requests.get("https://httpbin.org/delay/10", timeout=5)

Run it and wait about five seconds:

Terminal
$ python with_timeout.py
Traceback (most recent call last):
  File "with_timeout.py", line 4, in <module>
    response = requests.get("https://httpbin.org/delay/10", timeout=5)
  ...
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='httpbin.org', port=443):
Read timed out. (read timeout=5)

That timeout error is actually protecting your program. The message tells you the server didn't respond within 5 seconds, so requests stopped waiting and raised an exception. That's exactly what you want in a real application: fail clearly and quickly instead of hanging silently.

Rules of thumb

  • Always include timeout. Every requests.get() (and every other HTTP method) should have a timeout parameter.
  • Choose reasonable values. 5 to 10 seconds works for most APIs; use 30 seconds or more only for truly slow operations.
  • Handle timeout errors. Use try/except blocks (which we'll cover in Section 7) to catch these exceptions and react appropriately.
  • Test your timeout behaviour. Use httpbin.org/delay while developing to verify that your code handles slow responses gracefully.

Next, we'll look at what else the response object is telling you: status codes, headers, and the bits of metadata that let you diagnose a request at a glance.