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

  1. Inspect: kubectl get ds <name> -n <ns> -o jsonpath='{.spec.selector}'
  2. Repair the selector to match the pod template labels and re-apply
  3. 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

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


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