geektutu/7days-golang · error
rpc discovery: no available servers
Error message
rpc discovery: no available servers
What it means
Guard in MultiServersDiscovery.Get: the discovery instance's server list is empty (n == 0), so no peer can be selected under any SelectMode. It fires when Update was never called or the known set of servers shrank to nothing.
Source
Thrown at gee-rpc/day7-registry/xclient/discovery.go:55
func (d *MultiServersDiscovery) Refresh() error {
return nil
}
// Update the servers of discovery dynamically if needed
func (d *MultiServersDiscovery) Update(servers []string) error {
d.mu.Lock()
defer d.mu.Unlock()
d.servers = servers
return nil
}
// Get a server according to mode
func (d *MultiServersDiscovery) Get(mode SelectMode) (string, error) {
d.mu.Lock()
defer d.mu.Unlock()
n := len(d.servers)
if n == 0 {
return "", errors.New("rpc discovery: no available servers")
}
switch mode {
case RandomSelect:
return d.servers[d.r.Intn(n)], nil
case RoundRobinSelect:
s := d.servers[d.index%n] // servers could be updated, so mode n to ensure safety
d.index = (d.index + 1) % n
return s, nil
default:
return "", errors.New("rpc discovery: not supported select mode")
}
}
// returns all servers in discovery
func (d *MultiServersDiscovery) GetAll() ([]string, error) {
d.mu.RLock()
defer d.mu.RUnlock()
// return a copy of d.serversView on GitHub (pinned to cf36443821)
Solutions
- Register at least one server instance under the expected prefix in the registry before creating clients
- Verify the registry address and service prefix match between server registration and client discovery
- Wait for/watch the initial discovery update (registryWatcher) before issuing calls; add a readiness check or brief retry
- Handle the error in XClient call paths by refreshing discovery (call d.Update/refreshAndReportToCache) or surfacing 'no backends' to the user
Example fix
// before
d := xclient.NewGeeDiscovery(registry, "@geerpc/"+service) // no servers registered yet
client := xclient.NewXClient(d, xclient.RandomSelect, ...)
// after
// ensure servers register first, then poll for availability
for i := 0; i < 10; i++ {
if _, err := d.GetAll(); err == nil && len(servers) > 0 { break }
time.Sleep(500 * time.Millisecond)
} Defensive patterns
Strategy: retry
Validate before calling
func hasServers(d *xclient.MultiServersDiscovery) bool {
servers, err := d.GetAll()
return err == nil && len(servers) > 0
}
// wait for the registry to populate before creating/calling the client Try / catch
for attempt := 0; attempt < 5; attempt++ {
err := xc.Call(ctx, "Foo.Sum", args, &reply)
if err == nil { break }
if strings.Contains(err.Error(), "no available servers") {
time.Sleep(500 * time.Millisecond) // registry may not be populated yet
continue
}
return err
} Prevention
- Ensure backends register in etcd/registry before clients start calling
- Match the registry address and service prefix exactly between server and client
- Monitor registry instance counts and alert when zero servers remain
- Add a readiness delay or watch-event wait before issuing the first call
When it happens
Trigger: Creating GeeDiscovery/MultiServersDiscovery with an empty servers slice, constructing a Geo-based client whose initial registry push has not arrived yet, or all servers being removed via Update and then calling Get.
Common situations: Registry (etcd) has no registered servers for the service; service prefix wrong so no instances are fetched; calling a client before the registry watcher populates the list; every backend deregistered after crashes.
Related errors
- rpc discovery: not supported select mode
- rpc client: call failed:
- number of options is more than 1
- rpc server: service/method request ill-formed:
- rpc server: can't find service
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/e9e6fda80178c28e.
Report an issue: GitHub.