k3s-io/k3s · error
no server found for %s
Error message
no server found for %s
What it means
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.
Source
Thrown at pkg/agent/loadbalancer/servers.go:195
// getServer returns the first server with the specified address
func (sl *serverList) getServer(address string) *server {
sl.mutex.Lock()
defer sl.mutex.Unlock()
if i := slices.IndexFunc(sl.servers, func(s *server) bool { return s.address == address }); i != -1 {
return sl.servers[i]
}
return nil
}
// setHealthCheck updates the health check function for a server, replacing the
// current function.
func (sl *serverList) setHealthCheck(address string, healthCheck HealthCheckFunc) error {
if s := sl.getServer(address); s != nil {
s.healthCheck = healthCheck
return nil
}
return fmt.Errorf("no server found for %s", address)
}
// recordSuccess records a successful check of a server, either via health-check or dial.
// The server's state is adjusted accordingly.
func (sl *serverList) recordSuccess(srv *server, r reason) {
var new_state state
switch srv.state {
case stateFailed, stateUnchecked:
// dialed or health checked OK once, improve to recovering
new_state = stateRecovering
case stateRecovering:
if r == reasonHealthCheck {
// was recovering due to successful dial or first health check, can now improve
if len(srv.connections) > 0 {
// server accepted connections while recovering, attempt to go straight to active
new_state = stateActive
} else {
// no connections, just make it preferredView on GitHub (pinned to 6ba341e396)
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
Example fix
// before lb.SetHealthCheck(addr, fn) // addr not in the list yet // after lb.Update(append(lb.ServerAddresses(), addr)) lb.SetHealthCheck(addr, fn)
Defensive patterns
Strategy: validation
Validate before calling
found := false
for _, a := range lb.ServerAddresses() {
if a == addr {
found = true
break
}
}
if !found {
lb.Update(append(lb.ServerAddresses(), addr))
}
lb.SetHealthCheck(addr, fn) Prevention
- 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
When it happens
Trigger: 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.
Common situations: Custom integrations wiring health probes into the agent's LB; reconfiguring server addresses concurrently with startup.
Related errors
- token must not be empty
- invalid snapshot operation
- unsupported proxy scheme: %s
- server %s is stopping
- unknown stage %s requested
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/b26c790381f18f7a.
Report an issue: GitHub.