Connect, read and request deadlines are three different timeouts
coreintermediateA single "timeout" setting is not enough for a network call — three distinct deadlines cover three distinct failure modes. A connect timeout bounds how long to wait for the TCP handshake/connection to be established at all. A read timeout bounds how long to wait for data once the connection is open (a server that accepted the connection but never responds). A request (or total) timeout bounds the entire call end to end, including retries or streaming reads that could otherwise continue indefinitely one chunk at a time. Setting only one of these leaves the other failure modes completely unbounded.
Think of it as
Ordering food at a restaurant has the same three deadlines. The connect timeout is how long you wait for someone to even come take your order — if nobody shows up in five minutes, you leave, no food was ever discussed. The read timeout is how long you wait between the waiter saying "I'll check on that" and them actually coming back — if they vanish for 40 minutes mid-conversation, something is wrong even though the "connection" (your table) is still technically open. The request timeout is a hard rule for the whole meal — even if the waiter keeps coming back with small updates every few minutes forever, you still have to leave for your next appointment at some point regardless of how the individual check-ins went.
What we're doing: Show a read-timeout-only configuration failing to bound a slow-trickle response that a request timeout would have caught.
- 9
- Each individual chunk arrives well within the 5-second read timeout, so from the read timeout's perspective nothing is ever wrong.
- 12
- This is the gap: a read timeout only measures the wait between chunks, never the call's total duration — a request timeout is the only deadline that bounds this.
Why this works: This is the concrete reason a read timeout is not a substitute for a request timeout — a dependency does not need to go fully silent to hang a caller indefinitely, it only needs to keep the gaps between chunks just under the read-timeout threshold.
Setting only a read timeout and assuming it bounds the whole call
Wrong
Better
What you see: A request that should have failed fast instead hangs for minutes, consuming a thread or connection slot the whole time, while every individual timeout value in the configuration looks reasonable in isolation — the gap is that no single configured value actually bounds the total call duration.
Why: Many HTTP client libraries default a bare `timeout=N` parameter to only the read timeout (or a combined connect+read that still does not bound streaming/chunked responses) — assuming it covers the whole request leaves exactly the slow-trickle failure mode from the example above completely unbounded.
- Connect timeout — time to establish the connection
- Read timeout — time between chunks
- Request timeout — bounds the entire call
The three deadlines and what each one alone catches
Remember: A connect timeout bounds reaching the dependency at all; a read timeout bounds the wait between chunks once connected; a request timeout bounds the entire call. Setting only one leaves the other two failure modes completely unbounded — a chunked response trickling data just under the read timeout can hang forever without a request timeout to catch it.
See also: resource limit checklist · timeout budget composition · backoff and jitter

