People searching golang http client timeout, go http client timeout, golang http.client timeout, golang http timeout, golang http request timeout, golang http client default timeout, go http client default timeout, or pkg.go.dev net http client timeout zero means no timeout are usually trying to cap how long an outbound call can hang. Searches for golang http server timeout or client.timeout exceeded while awaiting headers golang sit on the other side: server deadlines and the exact client error when headers never arrive. Popular guides such as Ilija Eftimov’s server timeouts article stress layering client, Transport, context, and http.Server fields instead of relying on defaults—http.DefaultClient keeps Timeout == 0, which means no timeout until you set one.
Below, every client example hits the same dummy HTTP server built with httptest so you can go run one file with no separate terminal or Postman. For broader HTTP background, see HTTP in Go.
Tested with Go 1.24 on Linux.
Dummy backend with httptest
httptest.NewServer starts a real net/http.Server on a loopback port. The mux used in the full program exposes:
GET /late-headers— sleeps three seconds before sending status or body (good forClient.TimeoutandResponseHeaderTimeout).GET /late-body— sends200immediately, then sleeps three seconds before writing the body (headers arrive on time; body read can still hitClient.Timeout).
That split mirrors how awaiting response headers differs from reading the response body.
Client-side timeouts
http.Client.Timeout (golang http client timeout)
The Timeout field limits the entire call: dial (if needed), TLS, redirects, receiving headers, and reading the response body. The documentation states that a zero value means no timeout—that is the go http client default timeout behavior for http.DefaultClient.
If the server delays response headers past Timeout, you typically see:
Get "http://127.0.0.1:…/late-headers": context deadline exceeded (Client.Timeout exceeded while awaiting headers)If headers return quickly but the body is slow, cancellation can surface while reading the body (often wrapped as a timeout-style error mentioning Client.Timeout).
http.Transport (finer-grained golang http timeout)
http.Transport controls the connection pool and per-phase deadlines, including:
| Field | Role |
|---|---|
DialContext / net.Dialer.Timeout |
Cap TCP connect setup |
TLSHandshakeTimeout |
Cap TLS negotiation |
ResponseHeaderTimeout |
Cap wait for response headers after the request (including body) is fully written |
ExpectContinueTimeout |
Wait for 100 Continue when using Expect: 100-continue |
IdleConnTimeout |
How long an idle keep-alive connection may sit in the pool (not the same as end-to-end request time) |
When ResponseHeaderTimeout fires first, errors look like:
Get "http://127.0.0.1:…/late-headers": net/http: timeout awaiting response headersPrefer DialContext over the deprecated Transport.Dial field.
context.Context on the request (golang http request timeout)
http.NewRequestWithContext ties a single request to a deadline or cancellation. This is ideal when different RPCs need different budgets while sharing one http.Client. A typical error is plain context deadline exceeded.
Server-side timeouts (http.Server)
For production http.Server values, set explicit limits—common combinations appear in production writeups such as Eftimov’s resilient server timeouts guide:
| Field | Role |
|---|---|
ReadHeaderTimeout |
Time allowed to read request headers (mitigates slow clients) |
ReadTimeout |
Time allowed to read the entire request (headers + body) |
WriteTimeout |
Time allowed to write the response |
IdleTimeout |
Idle time before closing a keep-alive connection |
Zero means no limit for each field. httptest.NewUnstartedServer returns a server whose Config you can tweak before Start()—handy for reproducing short WriteTimeout behavior without binding a real port yourself.
http.TimeoutHandler adds a handler-level wall clock; it still needs enough server WriteTimeout budget to emit its timeout response.
Complete example: one file, all scenarios
Save as main.go, run go run . from a module (go mod init example.com/timeouts). The program builds the dummy server, then exercises client timeout, transport header timeout, context deadline, slow-body client timeout, and a tight server WriteTimeout (client may see EOF when the connection is closed mid-response).
package main
import (
"context"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"time"
)
func newTestServer() *httptest.Server {
mux := http.NewServeMux()
mux.HandleFunc("/late-headers", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
mux.HandleFunc("/late-body", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
time.Sleep(3 * time.Second)
_, _ = w.Write([]byte("body"))
})
return httptest.NewServer(mux)
}
func main() {
srv := newTestServer()
defer srv.Close()
base := srv.URL
fmt.Println("=== 1) http.Client.Timeout (headers late) ===")
c1 := &http.Client{Timeout: 2 * time.Second}
_, err := c1.Get(base + "/late-headers")
fmt.Println(err)
fmt.Println("\n=== 2) Transport.ResponseHeaderTimeout (headers late) ===")
tr := &http.Transport{
DialContext: (&net.Dialer{Timeout: 3 * time.Second}).DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 500 * time.Millisecond,
}
c2 := &http.Client{Transport: tr}
_, err = c2.Get(base + "/late-headers")
fmt.Println(err)
fmt.Println("\n=== 3) context.WithTimeout on request ===")
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, base+"/late-headers", nil)
_, err = http.DefaultClient.Do(req)
fmt.Println(err)
fmt.Println("\n=== 4) http.Client.Timeout while reading slow body ===")
c3 := &http.Client{Timeout: 1 * time.Second}
resp, err := c3.Get(base + "/late-body")
if err != nil {
fmt.Println(err)
} else {
_, err = io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Println(err)
}
fmt.Println("\n=== 5) http.Server WriteTimeout via httptest ===")
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(300 * time.Millisecond)
_, _ = w.Write([]byte("hello"))
})
us := httptest.NewUnstartedServer(h)
us.Config.WriteTimeout = 100 * time.Millisecond
us.Start()
defer us.Close()
_, err = http.Get(us.URL)
fmt.Println(err)
}Example output shape from a Linux run (addresses and ports vary):
=== 1) http.Client.Timeout (headers late) ===
Get "http://127.0.0.1:…/late-headers": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
=== 2) Transport.ResponseHeaderTimeout (headers late) ===
Get "http://127.0.0.1:…/late-headers": net/http: timeout awaiting response headers
=== 3) context.WithTimeout on request ===
Get "http://127.0.0.1:…/late-headers": context deadline exceeded
=== 4) http.Client.Timeout while reading slow body ===
context deadline exceeded (Client.Timeout or context cancellation while reading body)
=== 5) http.Server WriteTimeout via httptest ===
Get "http://127.0.0.1:…": EOFSummary
golang http client timeout and go http client timeout are usually solved with http.Client.Timeout (remember zero means no timeout per pkg.go.dev), optionally combined with http.Transport knobs such as ResponseHeaderTimeout for header stalls, and context.WithTimeout for per-request budgets—those map to golang http timeout, golang http request timeout, and the client.timeout exceeded while awaiting headers golang message when headers never arrive in time. golang http server timeout is a separate layer: ReadHeaderTimeout, ReadTimeout, WriteTimeout, and IdleTimeout on http.Server, plus optional http.TimeoutHandler. The httptest dummy server above reproduces both sides without manual curl or a second binary.
References
http.Client(Timeout field)http.Transporthttp.Server(timeout fields)httptestpackagehttp.TimeoutHandler- Resilient Go HTTP servers: timeouts and context (Ilija Eftimov)
Frequently Asked Questions
1. What does pkg.go.dev say about net http client timeout zero?
http.Client.Timeout means no timeout; the timer still applies once set and covers dial, redirects, and reading Response.Body (see the Client struct documentation on pkg.go.dev).2. Why do I see client.timeout exceeded while awaiting headers in golang?
http.Client.Timeout fires before response headers arrive; a short Transport.ResponseHeaderTimeout produces net/http: timeout awaiting response headers instead.3. golang http.client timeout vs golang http request timeout via context?
Client.Timeout is one setting for the whole client; context.WithTimeout on a single http.Request scopes that call only and composes with cancellation and deadlines.4. Should I set golang http server timeout fields?
ReadHeaderTimeout (slowloris mitigation), plus ReadTimeout, WriteTimeout, and IdleTimeout sized to your handlers; pair http.TimeoutHandler with enough WriteTimeout headroom if you wrap handlers.5. go http client default timeout value?
http.DefaultClient uses a zero Timeout, which means no deadline—fine for quick scripts, risky for production outbound calls.
