go-kratos/kratos · error
Discovery.GetService fetch failed
Error message
Discovery.GetService fetch failed
What it means
Returned by Discovery.GetService (contrib/registry/discovery/impl_discover.go:34) when r.fetch(ctx) reports ok=false. Looking at Resolve.fetch (discovery.go:421), ok is false when the app id is absent from the client's cached d.apps map or the zoneIns slot holds a non-disInstancesInfo value - i.e. the background poller has never successfully fetched this app from the discovery server. So the root cause is almost always upstream: the polls long-connection failed, the server is unreachable, or the app was never registered. The ctx argument is ignored by fetch, so cancelling the context does not produce this error.
Solutions
- Retry with backoff - the first poll may simply not have landed yet
- Verify the discovery server address in the client config and that the server is reachable (curl http://node/discovery/polls)
- Confirm the target app is registered (check the discovery console) and the app id string matches exactly
- Check the client logs for 'Discovery: polls failed' style errors which indicate the background fetch is failing
Example fix
// before
ins, err := d.GetService(ctx, "user.service")
if err != nil { return err } // fetch failed on cold start
// after
var ins []*registry.ServiceInstance
for attempt := 0; attempt < 5; attempt++ {
ins, err = d.GetService(ctx, "user.service")
if err == nil { break }
time.Sleep(time.Duration(attempt+1) * 200 * time.Millisecond)
} Defensive patterns
Strategy: retry
Try / catch
var ins []*registry.ServiceInstance
err := backoff.Retry(func() error {
var e error
ins, e = d.GetService(ctx, "user.service")
return e // retry while fetch fails / cache cold
}, backoff.WithMaxRetries(5)) Prevention
- Expect cold-start misses: build retry-with-backoff around initial GetService calls
- Health-check the discovery server endpoint before declaring an app missing
- Distinguish the two failures: 'fetch failed' = cache/poller problem, 'not found' = zone or registration problem
- Confirm d.config.Zone matches instances' registered zones or leave it empty
When it happens
Trigger: d.GetService(ctx, "user.service") before the first successful poll completes; discovery server down or the configured nodes unreachable so d.apps never populates; app id typo so no such app exists server-side (distinguish from the zone-empty case which yields 'Discovery.GetService(x) not found' instead); client just started and the poll goroutine has not finished its first request.
Common situations: Startup race where GetService is called immediately after creating the Discovery client; discovery node address misconfigured; network partition between the app and the discovery server; the target service crashed and its registration expired server-side.
Related errors
- ErrorCode
- discovery create watcher overtime
- register failed: instance duplicated:
- Discovery.GetService
- ErrorCode
AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16).
Data as JSON: /api/errors/3e81375ed5d07a41.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/registry/discovery/impl_discover.go:34
return nil
}
out := make([]*registry.ServiceInstance, 0, len(zoneInstance))
for _, v := range zoneInstance {
if v == nil {
continue
}
out = append(out, toServiceInstance(v))
}
return out
}
func (d *Discovery) GetService(ctx context.Context, serviceName string) ([]*registry.ServiceInstance, error) {
r := d.resolveBuild(serviceName)
ins, ok := r.fetch(ctx)
if !ok {
return nil, errors.New("Discovery.GetService fetch failed")
}
out := filterInstancesByZone(ins, d.config.Zone)
if len(out) == 0 {
return nil, fmt.Errorf("Discovery.GetService(%s) not found", serviceName)
}
return out, nil
}
func (d *Discovery) Watch(ctx context.Context, serviceName string) (registry.Watcher, error) {
return &watcher{
resolve: d.resolveBuild(serviceName),
serviceName: serviceName,
cancelCtx: ctx,
}, nil
}
View on GitHub (pinned to 668db92c2c)