{"record":{"id":"b26c790381f18f7a","repo":"k3s-io/k3s","slug":"no-server-found-for-s","errorCode":null,"errorMessage":"no server found for %s","messagePattern":"no server found for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/loadbalancer/servers.go","lineNumber":195,"sourceCode":"// getServer returns the first server with the specified address\nfunc (sl *serverList) getServer(address string) *server {\n\tsl.mutex.Lock()\n\tdefer sl.mutex.Unlock()\n\n\tif i := slices.IndexFunc(sl.servers, func(s *server) bool { return s.address == address }); i != -1 {\n\t\treturn sl.servers[i]\n\t}\n\treturn nil\n}\n\n// setHealthCheck updates the health check function for a server, replacing the\n// current function.\nfunc (sl *serverList) setHealthCheck(address string, healthCheck HealthCheckFunc) error {\n\tif s := sl.getServer(address); s != nil {\n\t\ts.healthCheck = healthCheck\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"no server found for %s\", address)\n}\n\n// recordSuccess records a successful check of a server, either via health-check or dial.\n// The server's state is adjusted accordingly.\nfunc (sl *serverList) recordSuccess(srv *server, r reason) {\n\tvar new_state state\n\tswitch srv.state {\n\tcase stateFailed, stateUnchecked:\n\t\t// dialed or health checked OK once, improve to recovering\n\t\tnew_state = stateRecovering\n\tcase stateRecovering:\n\t\tif r == reasonHealthCheck {\n\t\t\t// was recovering due to successful dial or first health check, can now improve\n\t\t\tif len(srv.connections) > 0 {\n\t\t\t\t// server accepted connections while recovering, attempt to go straight to active\n\t\t\t\tnew_state = stateActive\n\t\t\t} else {\n\t\t\t\t// no connections, just make it preferred","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/agent/loadbalancer/servers.go#L177-L213","documentation":"serverList.setHealthCheck (exposed via LoadBalancer.SetHealthCheck) looks up an entry by address with sl.getServer(address); if no server in the current list matches, it returns this error. It signals an ordering or programming mistake by the caller driving the embedded load balancer: the address was never added (Update/serverAddresses) or was removed before the call.","triggerScenarios":"Calling SetHealthCheck for an address not present in the serverList — after lb.Update replaced the address list, or before the address was ever added; races between config updates and health-check installation.","commonSituations":"Custom integrations wiring health probes into the agent's LB; reconfiguring server addresses concurrently with startup.","solutions":["Add/update the address first (lb.Update with the full address list) before installing the health check","Re-fetch the current address list and retry if concurrent updates are possible","Treat as a caller bug: log the target address plus lb.ServerAddresses() to pinpoint the mismatch"],"exampleFix":"// before\nlb.SetHealthCheck(addr, fn) // addr not in the list yet\n\n// after\nlb.Update(append(lb.ServerAddresses(), addr))\nlb.SetHealthCheck(addr, fn)","handlingStrategy":"validation","validationCode":"found := false\nfor _, a := range lb.ServerAddresses() {\n    if a == addr {\n        found = true\n        break\n    }\n}\nif !found {\n    lb.Update(append(lb.ServerAddresses(), addr))\n}\nlb.SetHealthCheck(addr, fn)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Order operations: lb.Update first, then SetHealthCheck","Serialize address-list updates and health-check installs to avoid races","Log ServerAddresses() alongside the failure to pinpoint the mismatch"],"tags":["loadbalancer","internal","api","ordering"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}