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

  1. Target a NodePort or LoadBalancer service (or a duplicate service of that type created for testing)
  2. Better: benchmark through a port-forward — pf to a backing pod and bench localhost instead of exposing the service
  3. Change service type temporarily to NodePort if network policy allows
  4. 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

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


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/3c4333f043c13477. Report an issue: GitHub.