derailed/k9s · error

expecting Service resource

Error message

expecting Service resource

What it means

StatefulSet.getStatefulSet converts the fetched unstructured object to appsv1.StatefulSet; on failure it returns 'expecting Service resource'. The message is a copy-paste from the Service DAO: the code is StatefulSet-specific and only the text is wrong. Semantics are identical to the StatefulSet conversion failure: the object's shape did not match appsv1.StatefulSet.

Source

Thrown at internal/dao/sts.go:109

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 {
		return nil, err
	}

	var sts appsv1.StatefulSet
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)
	if err != nil {
		return nil, errors.New("expecting Service resource")
	}

	return &sts, nil
}

// ScanSA scans for serviceaccount refs.
func (s *StatefulSet) ScanSA(_ context.Context, fqn string, wait bool) (Refs, error) {
	ns, n := client.Namespaced(fqn)
	oo, err := s.getFactory().List(s.gvr, ns, wait, labels.Everything())
	if err != nil {
		return nil, err
	}

	refs := make(Refs, 0, len(oo))
	for _, o := range oo {
		var sts appsv1.StatefulSet
		err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)
		if err != nil {

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Treat it as a StatefulSet conversion failure (the message text is wrong); verify the GVR passed to Init is client.StsGVR.
  2. Confirm apiVersion apps/v1 and a valid StatefulSet payload via kubectl get sts -o yaml.
  3. Correct the message locally or wrap the underlying conversion error to avoid the misleading text.

Example fix

// before (misleading copy-paste in internal/dao/sts.go getStatefulSet)
if err != nil { return nil, errors.New("expecting Service resource") }
// after
if err != nil { return nil, fmt.Errorf("expecting StatefulSet resource: %w", err) }
Defensive patterns

Strategy: type-guard

Validate before calling

if s.gvr != client.StsGVR.String() { // guard DAO misuse
    return nil, fmt.Errorf("statefulset DAO initialized with wrong gvr: %s", s.gvr)
}

Type guard

func isStatefulSet(o runtime.Object) bool {
    u, ok := o.(*unstructured.Unstructured)
    return ok && u.GetKind() == "StatefulSet"
}

Prevention

When it happens

Trigger: The object returned by s.getFactory().Get(s.gvr, fqn, ...) is not convertible to appsv1.StatefulSet — s.gvr misconfigured (pointing at a non-sts resource), apiVersion drift, or webhook-mutated fields that the typed converter rejects.

Common situations: Initializing the DAO with a GVR other than client.StsGVR; cluster/apiVersion upgrades; debugging confused by the wrong 'Service' wording pointing devs at the Service code path.

Related errors


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