derailed/k9s · warning

no valid selector found on Service %s

Error message

no valid selector found on Service %s

What it means

Service.TailLogs finds backing pods through the Service's spec.selector label map. The error fires when spec.selector is empty, meaning the Service selects no pods itself and log streaming via the Service is impossible.

Source

Thrown at internal/dao/svc.go:36

var (
	_ Accessor   = (*Service)(nil)
	_ Loggable   = (*Service)(nil)
	_ Controller = (*Service)(nil)
)

// Service represents a k8s service.
type Service struct {
	Resource
}

// TailLogs tail logs for all pods represented by this Service.
func (s *Service) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) {
	svc, err := s.GetInstance(opts.Path)
	if err != nil {
		return nil, err
	}
	if len(svc.Spec.Selector) == 0 {
		return nil, fmt.Errorf("no valid selector found on Service %s", opts.Path)
	}

	return podLogs(ctx, svc.Spec.Selector, opts)
}

// Pod returns a pod victim by name.
func (s *Service) Pod(fqn string) (string, error) {
	svc, err := s.GetInstance(fqn)
	if err != nil {
		return "", err
	}

	return podFromSelector(s.Factory, svc.Namespace, svc.Spec.Selector)
}

// GetInstance returns a service instance.
func (s *Service) GetInstance(fqn string) (*v1.Service, error) {
	o, err := s.getFactory().Get(s.gvr, fqn, true, labels.Everything())

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Check the type and selector: kubectl get svc <name> -o yaml | grep -A4 selector
  2. If pods should back it, fix the manifest: set spec.selector to the workload's labels and re-apply
  3. For ExternalName or selector-less Services, tail logs from the actual workload (Deployment/Pod) instead
  4. If endpoints are externally managed, find the target pods via kubectl get endpointslices -n <ns>

Example fix

# before: no selector
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  ports:
  - port: 80
# after: selector matching pods
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
  - port: 80
Defensive patterns

Strategy: validation

Validate before calling

svc, err := clientset.CoreV1().Services(ns).Get(ctx, name, metav1.GetOptions{})
if err != nil { return err }
if len(svc.Spec.Selector) == 0 {
    return fmt.Errorf("service %s selects no pods (type=%s); tail logs from the workload instead", name, svc.Spec.Type)
}

Type guard

func selectsPods(svc *corev1.Service) bool {
    return len(svc.Spec.Selector) > 0
}

Try / catch

chans, err := svcDAO.TailLogs(ctx, opts)
if err != nil {
    if strings.Contains(err.Error(), "no valid selector") {
        return errors.Join(err, fmt.Errorf("hint: ExternalName or selector-less Service has no pods"))
    }
    return err
}

Prevention

When it happens

Trigger: Invoking TailLogs on a Service with an empty selector: ExternalName services, headless Services that only own DNS records, Services delegating endpoint management to an EndpointSlice/external controller (e.g. custom ingress or external-dns patterns), or manifests where the selector block was accidentally dropped.

Common situations: ExternalName services (sql.example.com style DB pointers); manually managed EndpointSlices; selecting such a Service in k9s and hitting the logs shortcut.

Related errors


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