{"record":{"id":"3c4333f043c13477","repo":"derailed/k9s","slug":"you-must-select-a-reachable-service","errorCode":null,"errorMessage":"you must select a reachable service","messagePattern":"you must select a reachable service","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/view/svc.go","lineNumber":81,"sourceCode":"\tif err != nil {\n\t\ta.Flash().Err(err)\n\t\treturn\n\t}\n\tif svc.Spec.Type == v1.ServiceTypeExternalName {\n\t\ta.Flash().Warnf(\"No matching pods. Service %s is an external service.\", path)\n\t\treturn\n\t}\n\tif svc.Spec.Selector == nil {\n\t\ta.Flash().Warnf(\"No matching pods. Service %s does not provide any selectors\", path)\n\t\treturn\n\t}\n\n\tshowPods(a, path, labels.SelectorFromSet(svc.Spec.Selector), \"\")\n}\n\nfunc (*Service) checkSvc(svc *v1.Service) error {\n\tif svc.Spec.Type != \"NodePort\" && svc.Spec.Type != \"LoadBalancer\" {\n\t\treturn errors.New(\"you must select a reachable service\")\n\t}\n\treturn nil\n}\n\nfunc (*Service) getExternalPort(svc *v1.Service) (string, error) {\n\tif svc.Spec.Type == \"LoadBalancer\" {\n\t\treturn \"\", nil\n\t}\n\tports := render.ToPorts(svc.Spec.Ports)\n\tpp := strings.Split(ports, \" \")\n\t// Grab the first port pair for now...\n\ttokens := strings.Split(pp[0], \"►\")\n\tif len(tokens) < 2 {\n\t\treturn \"\", errors.New(\"no ports pair found\")\n\t}\n\n\treturn tokens[1], nil\n}","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/view/svc.go#L63-L99","documentation":"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`.","triggerScenarios":"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.","commonSituations":"Benchmarking default ClusterIP services created by `kubectl expose` or Helm charts; teams wanting load tests without exposing services externally.","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"],"exampleFix":"# before\nkind: Service\nspec:\n  type: ClusterIP   # benchmark rejected\n# after\nkind: Service\nspec:\n  type: NodePort     # benchmark allowed","handlingStrategy":"validation","validationCode":"t := svc.Spec.Type\nif t != v1.ServiceTypeNodePort && t != v1.ServiceTypeLoadBalancer {\n    return errors.New(\"you must select a reachable service\")\n}","typeGuard":"func externallyReachable(svc *v1.Service) bool {\n    return svc.Spec.Type == v1.ServiceTypeNodePort || svc.Spec.Type == v1.ServiceTypeLoadBalancer\n}","tryCatchPattern":null,"preventionTips":["Benchmark only NodePort/LB services","Use port-forward to pods for internal services","Wait for LB ingress IP before benching"],"tags":["kubernetes","service","benchmark","networking","k9s"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}