{"record":{"id":"ce780a4b4b3bdfe4","repo":"derailed/k9s","slug":"expecting-deployment-resource","errorCode":null,"errorMessage":"expecting Deployment resource","messagePattern":"expecting Deployment resource","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/dp.go","lineNumber":96,"sourceCode":"\tdp, err := d.GetInstance(fqn)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn podFromSelector(d.Factory, dp.Namespace, dp.Spec.Selector.MatchLabels)\n}\n\n// GetInstance fetch a matching deployment.\nfunc (d *Deployment) GetInstance(fqn string) (*appsv1.Deployment, error) {\n\to, err := d.Factory.Get(d.gvr, fqn, true, labels.Everything())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar dp appsv1.Deployment\n\terr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)\n\tif err != nil {\n\t\treturn nil, errors.New(\"expecting Deployment resource\")\n\t}\n\n\treturn &dp, nil\n}\n\n// ScanSA scans for serviceaccount refs.\nfunc (d *Deployment) ScanSA(_ context.Context, 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 dp appsv1.Deployment\n\t\terr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)\n\t\tif err != nil {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/dp.go#L78-L114","documentation":"k9s's Deployment DAO fetches a single Deployment from the shared informer cache as *unstructured.Unstructured and converts it into appsv1.Deployment via runtime.DefaultUnstructuredConverter.FromUnstructured (internal/dao/dp.go:96). The sentinel 'expecting Deployment resource' is returned when conversion fails; the underlying converter error is dropped, so the real offending field is invisible. It means the cached object under deployments.apps does not fit the k8s.io/api schema k9s was compiled against.","triggerScenarios":"Calling dao.Deployment.GetInstance(fqn) — the deployment detail view, restart, scale or image actions — when the stored object has a field whose JSON type cannot be assigned to the compiled appsv1.Deployment struct: apiserver version skew, an aggregated API or CRD shadowing deployments.apps, or webhook-patched out-of-schema values.","commonSituations":"Old k9s builds against new clusters (or the reverse) where deployment spec/status fields changed shape; custom mutating webhooks writing extra fields; GitOps tools force-applying legacy manifests; embedding the DAO layer with a custom factory whose cache holds converted objects.","solutions":["Inspect the object: kubectl get deployment.apps <name> -n <ns> -o yaml and look for unexpected or mistyped fields; fix via kubectl edit.","Upgrade k9s so its vendored k8s.io/* versions match the cluster minor version.","Confirm deployments.apps is served by the core apiserver and not shadowed (kubectl api-resources --api-group=apps).","Restart k9s to rebuild informer caches after cluster or webhook changes.","If embedding, wrap the converter error with %w to reveal the offending field."],"exampleFix":"// before\nerr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)\nif err != nil {\n    return nil, errors.New(\"expecting Deployment resource\")\n}\n// after\nu, ok := o.(*unstructured.Unstructured)\nif !ok {\n    return nil, fmt.Errorf(\"expected unstructured deployment, got %T\", o)\n}\nvar dp appsv1.Deployment\nif err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &dp); err != nil {\n    return nil, fmt.Errorf(\"deployment %q does not match v1 schema: %w\", fqn, err)\n}","handlingStrategy":"try-catch","validationCode":"o, err := factory.Get(client.DpGVR, fqn, true, labels.Everything())\nif err != nil { return err }\nu, ok := o.(*unstructured.Unstructured)\nif !ok || u.GroupVersionKind().Kind != \"Deployment\" {\n    return fmt.Errorf(\"not a deployment: %s\", u.GroupVersionKind())\n}","typeGuard":"func isDeployment(o runtime.Object) bool {\n    u, ok := o.(*unstructured.Unstructured)\n    return ok && u.GroupVersionKind().Kind == \"Deployment\" && u.GroupVersionKind().Group == \"apps\"\n}","tryCatchPattern":"var dp appsv1.Deployment\nif err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &dp); err != nil {\n    return nil, fmt.Errorf(\"deployment %q conversion: %w\", fqn, err)\n}","preventionTips":["Keep k9s's k8s.io/* dependencies aligned with the cluster minor version.","Avoid kubectl patch --type=merge with values whose types differ from the schema.","Assert *unstructured.Unstructured and check the GVK before converting in custom code.","Restart k9s after cluster upgrades to refresh informer caches."],"tags":["kubernetes","go","type-conversion","deployment","dao"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}