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/day4-timeout enforces opt.ConnectTimeout on the asynchronous dial handshake. If the connection is not established (and options not exchanged) within that window, it returns "rpc client: connect timeout: expect within %s" and abandons the attempt even though the goroutine may still complete later.

Source

Thrown at gee-rpc/day4-timeout/client.go:269

	}
	// 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...)
}

View on GitHub (pinned to cf36443821)

Solutions

  1. Increase opt.ConnectTimeout to comfortably exceed worst-case connect + options-exchange time
  2. Verify the server is running and reachable at the address (telnet/nc the port)
  3. Leave ConnectTimeout as 0 to disable the deadline and use the OS connect timeout
  4. Check for silent firewall drops between client and server

Example fix

// before
opt := &geerpc.Option{ConnectTimeout: 10 * time.Millisecond}
client, err := geerpc.Dial("tcp", "remote:9000", opt)
// after
opt := &geerpc.Option{ConnectTimeout: 3 * time.Second}
client, err := geerpc.Dial("tcp", "remote:9000", opt)
Defensive patterns

Strategy: retry

Validate before calling

if opt.ConnectTimeout != 0 && opt.ConnectTimeout < 500*time.Millisecond {
	return errors.New("ConnectTimeout too small; use >= 500ms or 0 to disable")
}

Try / catch

client, err := geerpc.Dial("tcp", addr, opt)
if err != nil && strings.Contains(err.Error(), "connect timeout") {
	time.Sleep(500 * time.Millisecond)
	client, err = geerpc.Dial("tcp", addr, opt) // bounded retry
}

Prevention

When it happens

Trigger: Dial with an Option whose ConnectTimeout > 0 while net.Dial plus NewClient (option exchange) exceed the deadline — slow/unreachable host, DNS stall, firewalled port, or a ConnectTimeout set shorter than network RTT.

Common situations: Server not listening (port closed, firewall silently dropping); wrong address in tests/CI without the server up; ConnectTimeout of a few milliseconds in a latency-sensitive environment; server accepting TCP but never responding to the options header.

Understand the failure class

Related errors


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/c3c8fe1cd91824d8. Report an issue: GitHub.