derailed/k9s · error
no valid selector found on daemonset %q
Error message
no valid selector found on daemonset %q
What it means
DaemonSet.TailLogs (internal/dao/ds.go:58-68) locates a DaemonSet's pods through spec.selector.matchLabels to fan out log streams. If the selector is nil or matchLabels is empty, pod discovery is impossible and it refuses with this error naming the DaemonSet path.
Source
Thrown at internal/dao/ds.go:65
}
return render.ExtractImages(&ds.Spec.Template.Spec), nil
}
// Restart a DaemonSet rollout.
func (d *DaemonSet) Restart(ctx context.Context, path string, opts *metav1.PatchOptions) error {
return restartRes[*appsv1.DaemonSet](ctx, d.getFactory(), client.DsGVR, path, opts)
}
// TailLogs tail logs for all pods represented by this DaemonSet.
func (d *DaemonSet) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) {
ds, err := d.GetInstance(opts.Path)
if err != nil {
return nil, err
}
if ds.Spec.Selector == nil || len(ds.Spec.Selector.MatchLabels) == 0 {
return nil, fmt.Errorf("no valid selector found on daemonset %q", opts.Path)
}
return podLogs(ctx, ds.Spec.Selector.MatchLabels, opts)
}
func podLogs(ctx context.Context, sel map[string]string, opts *LogOptions) ([]LogChan, error) {
f, ok := ctx.Value(internal.KeyFactory).(*watch.Factory)
if !ok {
return nil, errors.New("expecting a context factory")
}
ls, err := metav1.ParseToLabelSelector(toSelector(sel))
if err != nil {
return nil, err
}
lsel, err := metav1.LabelSelectorAsSelector(ls)
if err != nil {
return nil, err
}View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Inspect: kubectl get ds <name> -n <ns> -o jsonpath='{.spec.selector}'
- Repair the selector to match the pod template labels and re-apply
- Workaround: tail logs from the pods view, or select pods manually by the template's own labels
Defensive patterns
Strategy: validation
Validate before calling
// Guard before tailing: the daemonset must expose a usable selector.
func HasSelector(ds *appsv1.DaemonSet) bool {
return ds.Spec.Selector != nil && len(ds.Spec.Selector.MatchLabels) > 0
} Type guard
func SelectableDaemonSet(ds *appsv1.DaemonSet) (map[string]string, error) {
if ds.Spec.Selector == nil || len(ds.Spec.Selector.MatchLabels) == 0 {
return nil, fmt.Errorf("no valid selector found on daemonset %q", ds.Name)
}
return ds.Spec.Selector.MatchLabels, nil
} Try / catch
ds, err := d.GetInstance(opts.Path)
if err != nil { return nil, err }
if sel, serr := SelectableDaemonSet(ds); serr == nil {
return podLogs(ctx, sel, opts)
} else {
return podLogs(ctx, ds.Spec.Template.Labels, opts) // fallback via template labels
} Prevention
- Enforce non-empty selectors with admission policy (Kyverno rule on apps/v1 DaemonSet)
- Chart authors: unit-test rendered selectors against empty values
- Tail from the pods view when a DaemonSet is known-broken
When it happens
Trigger: Tail-logs on a DaemonSet whose spec.selector is absent or has an empty matchLabels map - an object that is invalid by current API validation but can exist via permissive creation paths (old charts, webhooks, direct API writes bypassing validation).
Common situations: Templated Helm charts with conditionally-empty selectors; DaemonSets created against very old API versions; malformed manifests applied with --validate=false.
Related errors
- no valid selector found on deployment: %s
- no matching pods for %v
- expecting DaemonSet resource
- expecting StatefulSet resource
- failed to locate pod %q: %w
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/8d06a6f40e295493.
Report an issue: GitHub.