Contact
Evil Genius SocietyHomeLearnForumLeaderboardSocialsMessages
← Back to module

Lesson 5 of 8

Network calls fail in ways local code never does. The server might be down, the connection might drop, DNS might fail, or the response might simply take forever. Module 6's try/except is what you need — this lesson is about what to catch.

Always set a timeout

By default, requests waits forever. A hung server hangs your program with it:

import requests

response = requests.get("https://api.example.com/data", timeout=10)

Treat timeout= as mandatory on every request. Ten seconds is a reasonable default.

raise_for_status()

Lesson 8.1 checked .status_code by hand. raise_for_status() turns a 4xx or 5xx into an exception instead:

import requests

try:
    response = requests.get("https://api.example.com/data", timeout=10)
    response.raise_for_status()
    data = response.json()
except requests.exceptions.HTTPError as e:
    print(f"Bad status: {e}")

Both styles are fine. Use if response.ok when a 404 is an expected outcome you want to handle inline; use raise_for_status() when any bad status is exceptional.

The exceptions to know

All of them inherit from requests.exceptions.RequestException:

| Exception | Cause | | --- | --- | | Timeout | took longer than timeout | | ConnectionError | DNS failure, refused connection, no network | | HTTPError | raised by raise_for_status() on 4xx/5xx | | TooManyRedirects | redirect loop | | RequestException | the base class — catches all of the above |

A robust call handles the specific ones it can act on, then falls back to the base class:

import requests

def fetch(url):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.Timeout:
        print("Request timed out")
    except requests.exceptions.ConnectionError:
        print("Could not connect")
    except requests.exceptions.HTTPError as e:
        print(f"Server returned an error: {e.response.status_code}")
    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}")
    return None

Order matters, exactly as in lesson 6.6: specific first, RequestException last.

Don't forget the JSON

.json() raises if the body isn't valid JSON — common when a server returns an HTML error page with a 200 status:

import json

def parse_body(text):
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return None

print(parse_body('{"ok": true}'))
print(parse_body("<html>Error page</html>"))

One catch worth knowing: json.JSONDecodeError is a subclass of ValueError. If you catch ValueError first, it will swallow JSON errors before a later except json.JSONDecodeError ever runs — the specific-before-general rule from lesson 6.6, with a trap hidden in the class hierarchy.

Retrying

Transient failures — a timeout, a 503 — are often worth one retry. Two rules:

  1. Only retry safe operations. A failed POST may have succeeded server-side (lesson 8.4).
  2. Back off exponentially. Waiting 1s, then 2s, then 4s gives a struggling server room to recover. Hammering it immediately makes things worse.
def compute_backoff(attempts):
    """Seconds to wait before each retry: 1, 2, 4, 8..."""
    return [2 ** i for i in range(attempts)]

print(compute_backoff(4))

In real code you'd time.sleep() between attempts, and give up after a few.

Never retry a 4xx — your request is wrong, and sending it again won't fix it. A 429 is the exception: it means slow down, and the response often includes a Retry-After header telling you how long to wait.

Try it yourself

Handle four different failure modes with one function.

Checkpoint

  • Always pass timeout= — the default is to wait forever.
  • raise_for_status() converts 4xx/5xx into an HTTPError.
  • Catch Timeout, ConnectionError, HTTPError, then RequestException as the catch-all.
  • .json() can fail too — a 200 doesn't guarantee valid JSON.
  • Retry only safe operations, with exponential backoff; never retry a 4xx except 429.

Questions about this lesson

Log in to ask a question.