An SDK should ship finite defaults for connecting, reading and the whole call, and fail with a clear timeout error rather than hang. Choose numbers from your own latency data, expose them as settings, and document them. A client that can wait forever turns a slow server into a stuck application.
Why "no timeout" is a bad default
Some popular HTTP libraries wait indefinitely unless told otherwise. The documentation for the Python requests library says nearly all production code should use the timeout parameter in nearly all requests, warns that failure to do so can cause the program to hang indefinitely, and states that if no timeout is specified explicitly, requests do not time out. It also notes the value is not a limit on the whole download: an exception is raised if the server has not sent a response for that many seconds, more precisely if no bytes have been received on the socket for that long. Go's standard HTTP client has a similar trap, covered in Go's http.Client has no timeout by default.
If your SDK wraps such a client and does not set a timeout, every customer inherits the hang. A hung request holds threads, connections and memory, and during an outage it can take the customer's service down with yours.
Three different timeouts
| Timeout | What it bounds | Typical failure it prevents |
|---|---|---|
| Connect | Time to establish the connection | Unreachable host, blackholed packets |
| Read | Gap between bytes received | Server accepts but never answers |
| Total deadline | Whole call including retries | Slow trickle responses, retry storms |
The read timeout alone, as the requests documentation notes, does not cap total time. A server that sends one byte every few seconds can keep a call alive for a very long time, so add a total deadline in your SDK.
Steps to choose and ship defaults
- Measure real latency for each endpoint at the high percentiles, in normal and busy periods.
- Set the default connect timeout short, since connection setup should be fast or fail.
- Set the read timeout above your slowest normal response, with headroom, and allow per endpoint overrides for known slow operations such as exports.
- Add a total deadline that covers retries, so the loop described in safe retry rules cannot run unbounded.
- Raise a distinct error type for timeouts, separate from authentication and server errors, so callers can handle them.
- Make the defaults visible: print them in docs, and show how to change them in one line.
- Treat a change to default timeouts as a notable change in the changelog, because it alters behavior for every caller.
- Test with a local server that accepts a connection and never responds, and another that sends one byte at a time.
What not to do
Do not set a very large timeout to "avoid false failures". A ten minute default is nearly the same as none. Do not retry timeouts on non idempotent requests without a duplicate guard, since the first request may have succeeded. And do not swallow the error: return it, with the request ID if you have one.
For server owners
Mirror the client defaults on your side. Set server timeouts for slow headers, slow bodies and idle connections so clients that misbehave cannot hold resources open. OWASP lists execution timeouts among the limits an API should enforce, in its entry on unrestricted resource consumption.
Quick check
Does a read timeout cap the whole request?
No. It bounds the gap between bytes. Add a total deadline to cap the whole call.
Should callers be able to change the timeouts?
Yes, per client and per call, with documented defaults. The defaults protect people who never look.
Safeguard's dependency scanning and SBOM inventory can show which HTTP client library and version sit under your SDK. Try the free scan.
Sources
- Requests documentation: Quickstart, Timeouts
- OWASP API Security Top 10 2023: API4 Unrestricted Resource Consumption
Last reviewed: 19 October 2026.