derailed/k9s · warning
you must select a reachable service
Error message
you must select a reachable service
What it means
Flashed by `Service.checkSvc` (internal/view/svc.go:79) from `toggleBenchCmd` when starting an HTTP benchmark on a service whose `spec.type` is neither `NodePort` nor `LoadBalancer`. The benchmark dials the service from outside via its external address, and a ClusterIP (or ExternalName/Headless) service has no externally reachable endpoint, so the run is rejected before `getExternalPort`.
Source
Thrown at internal/view/svc.go:81
if err != nil {
a.Flash().Err(err)
return
}
if svc.Spec.Type == v1.ServiceTypeExternalName {
a.Flash().Warnf("No matching pods. Service %s is an external service.", path)
return
}
if svc.Spec.Selector == nil {
a.Flash().Warnf("No matching pods. Service %s does not provide any selectors", path)
return
}
showPods(a, path, labels.SelectorFromSet(svc.Spec.Selector), "")
}
func (*Service) checkSvc(svc *v1.Service) error {
if svc.Spec.Type != "NodePort" && svc.Spec.Type != "LoadBalancer" {
return errors.New("you must select a reachable service")
}
return nil
}
func (*Service) getExternalPort(svc *v1.Service) (string, error) {
if svc.Spec.Type == "LoadBalancer" {
return "", nil
}
ports := render.ToPorts(svc.Spec.Ports)
pp := strings.Split(ports, " ")
// Grab the first port pair for now...
tokens := strings.Split(pp[0], "►")
if len(tokens) < 2 {
return "", errors.New("no ports pair found")
}
return tokens[1], nil
}View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Target a NodePort or LoadBalancer service (or a duplicate service of that type created for testing)
- Better: benchmark through a port-forward — pf to a backing pod and bench localhost instead of exposing the service
- Change service type temporarily to NodePort if network policy allows
- If a LoadBalancer service is pending an IP, wait for the ingress to be assigned before benching
Example fix
# before kind: Service spec: type: ClusterIP # benchmark rejected # after kind: Service spec: type: NodePort # benchmark allowed
Defensive patterns
Strategy: validation
Validate before calling
t := svc.Spec.Type
if t != v1.ServiceTypeNodePort && t != v1.ServiceTypeLoadBalancer {
return errors.New("you must select a reachable service")
} Type guard
func externallyReachable(svc *v1.Service) bool {
return svc.Spec.Type == v1.ServiceTypeNodePort || svc.Spec.Type == v1.ServiceTypeLoadBalancer
} Prevention
- Benchmark only NodePort/LB services
- Use port-forward to pods for internal services
- Wait for LB ingress IP before benching
When it happens
Trigger: Pressing the benchmark key (shift-b) on a service with spec.type=ClusterIP — checkSvc returns the error and the flash shows it; LoadBalancer and NodePort pass.
Common situations: Benchmarking default ClusterIP services created by `kubectl expose` or Helm charts; teams wanting load tests without exposing services externally.
Related errors
- no valid selector found on Service %s
- invalid benchmark host %q
- expecting Service resource
- failed benchmark
- node is cordoned
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/3c4333f043c13477.
Report an issue: GitHub.