{"record":{"id":"3e81375ed5d07a41","repo":"go-kratos/kratos","slug":"discovery-getservice-fetch-failed","errorCode":null,"errorMessage":"Discovery.GetService fetch failed","messagePattern":"Discovery\\.GetService fetch failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"contrib/registry/discovery/impl_discover.go","lineNumber":34,"sourceCode":"\t\treturn nil\n\t}\n\n\tout := make([]*registry.ServiceInstance, 0, len(zoneInstance))\n\tfor _, v := range zoneInstance {\n\t\tif v == nil {\n\t\t\tcontinue\n\t\t}\n\t\tout = append(out, toServiceInstance(v))\n\t}\n\n\treturn out\n}\n\nfunc (d *Discovery) GetService(ctx context.Context, serviceName string) ([]*registry.ServiceInstance, error) {\n\tr := d.resolveBuild(serviceName)\n\tins, ok := r.fetch(ctx)\n\tif !ok {\n\t\treturn nil, errors.New(\"Discovery.GetService fetch failed\")\n\t}\n\n\tout := filterInstancesByZone(ins, d.config.Zone)\n\tif len(out) == 0 {\n\t\treturn nil, fmt.Errorf(\"Discovery.GetService(%s) not found\", serviceName)\n\t}\n\n\treturn out, nil\n}\n\nfunc (d *Discovery) Watch(ctx context.Context, serviceName string) (registry.Watcher, error) {\n\treturn &watcher{\n\t\tresolve:     d.resolveBuild(serviceName),\n\t\tserviceName: serviceName,\n\t\tcancelCtx:   ctx,\n\t}, nil\n}\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/contrib/registry/discovery/impl_discover.go#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nins, err := d.GetService(ctx, \"user.service\")\nif err != nil { return err } // fetch failed on cold start\n\n// after\nvar ins []*registry.ServiceInstance\nfor attempt := 0; attempt < 5; attempt++ {\n    ins, err = d.GetService(ctx, \"user.service\")\n    if err == nil { break }\n    time.Sleep(time.Duration(attempt+1) * 200 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var ins []*registry.ServiceInstance\nerr := backoff.Retry(func() error {\n    var e error\n    ins, e = d.GetService(ctx, \"user.service\")\n    return e // retry while fetch fails / cache cold\n}, backoff.WithMaxRetries(5))","preventionTips":["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"],"tags":["registry","discovery","network","cold-start"],"backgroundTag":null,"analyzedSha":"668db92c2c001e9552594ba5a8aede8456af6d7e","analyzedAt":"2026-08-16T02:07:20.704Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}