derailed/k9s · warning
no valid selector found on statefulset: %s
Error message
no valid selector found on statefulset: %s
What it means
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.
Source
Thrown at internal/dao/sts.go:84
}
var sts appsv1.StatefulSet
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)
if err != nil {
return nil, errors.New("expecting Statefulset resource")
}
return &sts, nil
}
// TailLogs tail logs for all pods represented by this StatefulSet.
func (s *StatefulSet) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) {
sts, err := s.getStatefulSet(opts.Path)
if err != nil {
return nil, errors.New("expecting StatefulSet resource")
}
if sts.Spec.Selector == nil || len(sts.Spec.Selector.MatchLabels) == 0 {
return nil, fmt.Errorf("no valid selector found on statefulset: %s", opts.Path)
}
return podLogs(ctx, sts.Spec.Selector.MatchLabels, opts)
}
// Pod returns a pod victim by name.
func (s *StatefulSet) Pod(fqn string) (string, error) {
sts, err := s.getStatefulSet(fqn)
if err != nil {
return "", err
}
return podFromSelector(s.Factory, sts.Namespace, sts.Spec.Selector.MatchLabels)
}
func (s *StatefulSet) getStatefulSet(fqn string) (*appsv1.StatefulSet, error) {
o, err := s.getFactory().Get(s.gvr, fqn, true, labels.Everything())
if err != nil {View on GitHub (pinned to 2d3ccc6ba2)
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>
Example fix
# before: selector missing
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
template:
metadata:
labels:
app: db
# after: valid selector
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db Defensive patterns
Strategy: validation
Validate before calling
sts, err := clientset.AppsV1().StatefulSets(ns).Get(ctx, name, metav1.GetOptions{})
if err != nil { return err }
if sts.Spec.Selector == nil || len(sts.Spec.Selector.MatchLabels) == 0 {
return fmt.Errorf("statefulset %s has no selector; fix its spec before tailing logs", name)
}
// safe to call TailLogs now Type guard
func hasPodSelector(sts *appsv1.StatefulSet) bool {
return sts.Spec.Selector != nil && len(sts.Spec.Selector.MatchLabels) > 0
} Try / catch
chans, err := stsDAO.TailLogs(ctx, opts)
if err != nil {
if strings.Contains(err.Error(), "no valid selector") {
// surface actionable hint: workload spec is broken
return fmt.Errorf("cannot tail logs: %w — inspect spec.selector.matchLabels", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- no valid selector found on Service %s
- you must provide a selection
- no valid selector found on deployment: %s
- no valid selector found on daemonset %q
- user is not authorized to patch a statefulset
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/4bdf012df9c13e0b.
Report an issue: GitHub.