{"record":{"id":"4bdf012df9c13e0b","repo":"derailed/k9s","slug":"no-valid-selector-found-on-statefulset-s","errorCode":null,"errorMessage":"no valid selector found on statefulset: %s","messagePattern":"no valid selector found on statefulset: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/dao/sts.go","lineNumber":84,"sourceCode":"\t}\n\n\tvar sts appsv1.StatefulSet\n\terr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)\n\tif err != nil {\n\t\treturn nil, errors.New(\"expecting Statefulset resource\")\n\t}\n\n\treturn &sts, nil\n}\n\n// TailLogs tail logs for all pods represented by this StatefulSet.\nfunc (s *StatefulSet) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) {\n\tsts, err := s.getStatefulSet(opts.Path)\n\tif err != nil {\n\t\treturn nil, errors.New(\"expecting StatefulSet resource\")\n\t}\n\tif sts.Spec.Selector == nil || len(sts.Spec.Selector.MatchLabels) == 0 {\n\t\treturn nil, fmt.Errorf(\"no valid selector found on statefulset: %s\", opts.Path)\n\t}\n\n\treturn podLogs(ctx, sts.Spec.Selector.MatchLabels, opts)\n}\n\n// Pod returns a pod victim by name.\nfunc (s *StatefulSet) Pod(fqn string) (string, error) {\n\tsts, err := s.getStatefulSet(fqn)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn podFromSelector(s.Factory, sts.Namespace, sts.Spec.Selector.MatchLabels)\n}\n\nfunc (s *StatefulSet) getStatefulSet(fqn string) (*appsv1.StatefulSet, error) {\n\to, err := s.getFactory().Get(s.gvr, fqn, true, labels.Everything())\n\tif err != nil {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/sts.go#L66-L102","documentation":"StatefulSet.TailLogs resolves member pods via spec.selector.matchLabels before streaming logs. The error fires when the StatefulSet's selector is nil or has an empty matchLabels map, so no label query can be built. Without a selector there is no way to map the StatefulSet to its pods.","triggerScenarios":"Invoking TailLogs on a StatefulSet whose spec.selector is absent or empty. Valid StatefulSets rejected by kubectl apply validation can still exist when created by controllers, Helm with --force, or operators that bypass strict validation; hand-edited YAML with a typo'd or missing selector block also triggers it.","commonSituations":"Broken Helm charts or operators that omit spec.selector.matchLabels; StatefulSets patched in ways that stripped the selector; users pressing the log shortcut on such a malformed workload in k9s.","solutions":["Inspect the resource: kubectl get statefulset <name> -o yaml and check spec.selector.matchLabels","Fix the manifest/chart so spec.selector.matchLabels matches spec.template.metadata.labels and re-apply","Until fixed, stream logs from pods directly: kubectl logs -l <correct-labels> -n <ns>"],"exampleFix":"# before: selector missing\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: db\nspec:\n  template:\n    metadata:\n      labels:\n        app: db\n# after: valid selector\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: db\nspec:\n  selector:\n    matchLabels:\n      app: db\n  template:\n    metadata:\n      labels:\n        app: db","handlingStrategy":"validation","validationCode":"sts, err := clientset.AppsV1().StatefulSets(ns).Get(ctx, name, metav1.GetOptions{})\nif err != nil { return err }\nif sts.Spec.Selector == nil || len(sts.Spec.Selector.MatchLabels) == 0 {\n    return fmt.Errorf(\"statefulset %s has no selector; fix its spec before tailing logs\", name)\n}\n// safe to call TailLogs now","typeGuard":"func hasPodSelector(sts *appsv1.StatefulSet) bool {\n    return sts.Spec.Selector != nil && len(sts.Spec.Selector.MatchLabels) > 0\n}","tryCatchPattern":"chans, err := stsDAO.TailLogs(ctx, opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"no valid selector\") {\n        // surface actionable hint: workload spec is broken\n        return fmt.Errorf(\"cannot tail logs: %w — inspect spec.selector.matchLabels\", err)\n    }\n    return err\n}","preventionTips":["Validate StatefulSet manifests with kubectl apply --dry-run=server before they land","Warn on workloads whose selector doesn't intersect template labels at inventory time"],"tags":["kubernetes","statefulset","selector","logs","k9s"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}