geektutu/7days-golang · error
rpc client: connect timeout: expect within %s
Error message
rpc client: connect timeout: expect within %s
What it means
dialTimeout in gee-rpc/day5-http-debug enforces opt.ConnectTimeout on connection setup; exceeding it returns "rpc client: connect timeout: expect within %s". Unlike day4 it is also on the DialHTTP path, so HTTP-tunneled RPC clients face the same deadline.
Source
Thrown at gee-rpc/day5-http-debug/client.go:273
}
// close the connection if client is nil
defer func() {
if err != nil {
_ = conn.Close()
}
}()
ch := make(chan clientResult)
go func() {
client, err := f(conn, opt)
ch <- clientResult{client: client, err: err}
}()
if opt.ConnectTimeout == 0 {
result := <-ch
return result.client, result.err
}
select {
case <-time.After(opt.ConnectTimeout):
return nil, fmt.Errorf("rpc client: connect timeout: expect within %s", opt.ConnectTimeout)
case result := <-ch:
return result.client, result.err
}
}
// Dial connects to an RPC server at the specified network address
func Dial(network, address string, opts ...*Option) (*Client, error) {
return dialTimeout(NewClient, network, address, opts...)
}
// NewHTTPClient new a Client instance via HTTP as transport protocol
func NewHTTPClient(conn net.Conn, opt *Option) (*Client, error) {
_, _ = io.WriteString(conn, fmt.Sprintf("CONNECT %s HTTP/1.0\n\n", defaultRPCPath))
// Require successful HTTP response
// before switching to RPC protocol.
resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
if err == nil && resp.Status == connected {View on GitHub (pinned to cf36443821)
Solutions
- Raise opt.ConnectTimeout (e.g. 3-5s) to cover DNS + connect + options exchange
- Confirm the server/proxy is up and the port is reachable before dialing
- Set ConnectTimeout to 0 to disable the client-side deadline
- Add retry with backoff around Dial for transient latency spikes
Example fix
// before
opt := &geerpc.Option{ConnectTimeout: 50 * time.Millisecond}
client, err := geerpc.DialHTTP("tcp", "api.example.com/rpc", opt)
// after
opt := &geerpc.Option{ConnectTimeout: 5 * time.Second}
client, err := geerpc.DialHTTP("tcp", "api.example.com/rpc", opt) Defensive patterns
Strategy: retry
Validate before calling
if opt.ConnectTimeout != 0 && opt.ConnectTimeout < 500*time.Millisecond {
return errors.New("ConnectTimeout too aggressive for HTTP tunneled dial")
} Try / catch
client, err := geerpc.DialHTTP("tcp", addr, opt)
if err != nil && strings.Contains(err.Error(), "connect timeout") {
time.Sleep(time.Second)
client, err = geerpc.DialHTTP("tcp", addr, opt)
} Prevention
- Allow extra ConnectTimeout headroom when proxies sit between client and server
- Health-check the HTTP endpoint before dialing
- Prefer 0 (no deadline) in flaky network environments
- Wrap DialHTTP with bounded retries and backoff
When it happens
Trigger: Dial or DialHTTP with ConnectTimeout > 0 while the TCP connect plus options exchange (or the HTTP CONNECT-style handshake for DialHTTP) takes longer than the deadline; unreachable host or server that accepts but never answers.
Common situations: Reverse proxy or load balancer in front of the RPC server adding latency; server hung (accepting sockets but not reading); aggressive ConnectTimeout in ephemeral CI environments; DNS resolution delays.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- rpc client: connect timeout: expect within %s
- unexpected HTTP response:
- unexpected HTTP response:
- %s
- rpc client: connect timeout: expect within %s
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/669d831492e41b82.
Report an issue: GitHub.