{"record":{"id":"382b5427173af178","repo":"derailed/k9s","slug":"expecting-statefulset-resource","errorCode":null,"errorMessage":"expecting StatefulSet resource","messagePattern":"expecting StatefulSet resource","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/ds.go","lineNumber":178,"sourceCode":"\t}\n\n\treturn refs, nil\n}\n\n// Scan scans for cluster refs.\nfunc (d *DaemonSet) Scan(_ context.Context, gvr *client.GVR, fqn string, wait bool) (Refs, error) {\n\tns, n := client.Namespaced(fqn)\n\too, err := d.getFactory().List(d.gvr, ns, wait, labels.Everything())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trefs := make(Refs, 0, len(oo))\n\tfor _, o := range oo {\n\t\tvar ds appsv1.DaemonSet\n\t\terr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(\"expecting StatefulSet resource\")\n\t\t}\n\t\tswitch gvr {\n\t\tcase client.CmGVR:\n\t\t\tif !hasConfigMap(&ds.Spec.Template.Spec, n) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\trefs = append(refs, Ref{\n\t\t\t\tGVR: d.GVR(),\n\t\t\t\tFQN: client.FQN(ds.Namespace, ds.Name),\n\t\t\t})\n\t\tcase client.SecGVR:\n\t\t\tfound, err := hasSecret(d.Factory, &ds.Spec.Template.Spec, ds.Namespace, n, wait)\n\t\t\tif err != nil {\n\t\t\t\tslog.Warn(\"Unable to locate secret\",\n\t\t\t\t\tslogs.FQN, fqn,\n\t\t\t\t\tslogs.Error, err,\n\t\t\t\t)\n\t\t\t\tcontinue","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/ds.go#L160-L196","documentation":"DaemonSet.Scan converts every DaemonSet in a namespace into appsv1.DaemonSet to find ConfigMap, Secret and PVC references (internal/dao/ds.go:178). The message is misleading: the code converts appsv1.DaemonSet but the sentinel says 'expecting StatefulSet resource' — a copy-paste from the StatefulSet scanner. Functionally it still means FromUnstructured could not fit a cached daemonsets.apps object into the compiled struct, and one bad object aborts the whole scan.","triggerScenarios":"Opening an xray or reference scan (CmGVR, SecGVR, PvcGVR) in a namespace where a stored DaemonSet fails conversion to the compiled appsv1.DaemonSet struct — version skew, GVR shadowing, or webhook-written out-of-schema fields. When debugging, ignore the StatefulSet wording and inspect daemonsets.","commonSituations":"Developers chasing a phantom StatefulSet problem because the message names the wrong kind; xray views failing after cluster upgrades on older k9s builds; DaemonSets mutated by legacy tooling.","solutions":["Do not search StatefulSets — the message is wrong; inspect kubectl get daemonsets.apps -n <ns> -o yaml for mistyped fields.","Upgrade k9s (newer builds may fix the message and keep conversion schemas current).","Fix the message locally or upstream: change ds.go:178 to 'expecting DaemonSet resource'.","Wrap the converter error with %w to expose the offending field.","Patch the loop to skip unparsable objects with a warning instead of aborting the scan."],"exampleFix":"// before (ds.go:178 — message copy-pasted from sts.go)\nreturn nil, errors.New(\"expecting StatefulSet resource\")\n// after\nif err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ds); err != nil {\n    slog.Warn(\"skip unparsable daemonset\", \"fqn\", client.FQN(u.GetNamespace(), u.GetName()), \"err\", err)\n    continue\n}","handlingStrategy":"try-catch","validationCode":"for _, o := range oo {\n    u, ok := o.(*unstructured.Unstructured)\n    if !ok || u.GroupVersionKind().Kind != \"DaemonSet\" {\n        continue\n    }\n    // safe to convert below\n}","typeGuard":"func isDaemonSet(o runtime.Object) bool {\n    u, ok := o.(*unstructured.Unstructured)\n    return ok && u.GroupVersionKind().Kind == \"DaemonSet\" && u.GroupVersionKind().Group == \"apps\"\n}","tryCatchPattern":"if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ds); err != nil {\n    slog.Warn(\"skip unparsable daemonset\", \"fqn\", fqn, \"err\", err)\n    continue // the stock message wrongly says StatefulSet; guard daemonsets\n}","preventionTips":["Do not trust resource names in error strings — verify the code path that prints them.","Make scans degrade per object with logging.","When patching k9s locally, fix the ds.go:178 message to say DaemonSet to save future debugging.","Align k9s and cluster versions to avoid conversion failures at the source."],"tags":["kubernetes","go","type-conversion","daemonset","error-message-bug"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}