{"record":{"id":"2f02d050abcd130e","repo":"cilium/cilium","slug":"unable-to-get-nodes-cluster-w","errorCode":null,"errorMessage":"unable to get nodes' cluster: %w","messagePattern":"unable to get nodes' cluster: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/health/server/server.go","lineNumber":96,"sourceCode":"}\n\n// getNodes fetches the nodes added and removed from the last time the server\n// made a request to the daemon.\nfunc (s *Server) getNodes() (nodeMap, nodeMap, error) {\n\tscopedLog := s.logger\n\tif s.CiliumURI != \"\" {\n\t\tscopedLog = s.logger.With(logfields.URI, s.CiliumURI)\n\t}\n\tscopedLog.Debug(\"Sending request for /cluster/nodes ...\")\n\n\tclusterNodesParam := daemon.NewGetClusterNodesParams()\n\ts.RWMutex.RLock()\n\tcID := s.clientID\n\ts.RWMutex.RUnlock()\n\tclusterNodesParam.SetClientID(&cID)\n\tresp, err := s.Daemon.GetClusterNodes(clusterNodesParam)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"unable to get nodes' cluster: %w\", err)\n\t}\n\tscopedLog.Debug(\"Got cilium /cluster/nodes\")\n\n\tif resp == nil || resp.Payload == nil {\n\t\treturn nil, nil, fmt.Errorf(\"received nil health response\")\n\t}\n\n\ts.RWMutex.Lock()\n\ts.clientID = resp.Payload.ClientID\n\n\tif resp.Payload.Self != \"\" {\n\t\ts.localStatus = &healthModels.SelfStatus{\n\t\t\tName: resp.Payload.Self,\n\t\t}\n\t}\n\ts.RWMutex.Unlock()\n\n\tnodesAdded := nodeElementSliceToNodeMap(resp.Payload.NodesAdded, option.Config.PreferIpv6)","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/health/server/server.go#L78-L114","documentation":"The cilium-health server's getNodes (pkg/health/server/server.go:96) asks the main Cilium daemon for the cluster node list via s.Daemon.GetClusterNodes (the /cluster/nodes API), which the health daemon uses to probe peer nodes. This error wraps any failure of that client call with %w.","triggerScenarios":"Daemon.GetClusterNodes(clusterNodesParam) returns an error: the agent API is unreachable (socket missing/refused), the request fails/times out, or the API returns an error payload.","commonSituations":"Agent restarting while health daemon probes continue; agent API socket permissions or path issues; API version skew between health server and daemon; agent overloaded causing request timeouts.","solutions":["Check the wrapped cause to distinguish socket-unreachable vs API error","Verify the Cilium agent is up and its API socket exists (cilium status)","Retry — getNodes is called from runActiveServices which repeats periodically; a transient agent restart self-heals","Confirm agent/health-daemon API versions match (no skewed upgrade)","Inspect agent logs for errors serving /cluster/nodes (e.g. KVStore/cluster connectivity problems)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if _, err := os.Stat(agentSocketPath); err != nil {\n\treturn fmt.Errorf(\"agent API socket unavailable: %w\", err) // skip probe round\n}","typeGuard":null,"tryCatchPattern":"nodes, _, err := getNodes(ctx)\nif err != nil {\n\tlog.WithError(err).Debug(\"getNodes failed; will retry next interval\")\n\treturn // runActiveServices retries periodically\n}","preventionTips":["Rely on runActiveServices' periodic retry for transient failures","Verify agent liveness before probing","Keep health server and agent versions aligned","Monitor agent API socket errors"],"tags":["cilium","health","api-client","cluster-nodes"],"backgroundTag":"api-request-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}