{"record":{"id":"08b104a2b43e8a7e","repo":"derailed/k9s","slug":"unable-to-find-controller-for-replicaset-s","errorCode":null,"errorMessage":"unable to find controller for replicaset: %s","messagePattern":"unable to find controller for replicaset: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/rs.go","lineNumber":84,"sourceCode":"\t\treturn 0, errors.New(\"revision conversion failed\")\n\t}\n\n\treturn int64(vers), nil\n}\n\nfunc controllerInfo(rs *appsv1.ReplicaSet) (name, kind, group string, err error) {\n\tfor _, ref := range rs.OwnerReferences {\n\t\tif ref.Controller == nil {\n\t\t\tcontinue\n\t\t}\n\t\tgroup, tokens := ref.APIVersion, strings.Split(ref.APIVersion, \"/\")\n\t\tif len(tokens) == 2 {\n\t\t\tgroup = tokens[0]\n\t\t}\n\t\treturn ref.Name, ref.Kind, group, nil\n\t}\n\n\treturn \"\", \"\", \"\", fmt.Errorf(\"unable to find controller for replicaset: %s\", rs.Name)\n}\n\n// Rollback reverses the last deployment.\nfunc (r *ReplicaSet) Rollback(fqn string) error {\n\trs, err := r.Load(r.Factory, fqn)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tversion, err := getRSRevision(rs)\n\tif err != nil {\n\t\treturn err\n\t}\n\tname, kind, apiGroup, err := controllerInfo(rs)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdial, err := r.Client().Dial()","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/rs.go#L66-L102","documentation":"controllerInfo walks a ReplicaSet's ownerReferences for an entry with controller=true to identify its managing controller (normally a Deployment) — required to build rollback info. ReplicaSets created standalone, or orphaned by deleting their Deployment with --cascade=orphan, have no controller ref, so the lookup fails and names the RS.","triggerScenarios":"Calling ReplicaSet.Rollback on an RS whose ownerReferences are empty or lack a controller=true entry.","commonSituations":"kubectl delete deployment <d> --cascade=orphan during migration leaving live RSs; RSs created directly by manifests or older tooling; ownership stripped by webhook mutations.","solutions":["Roll back via the owning Deployment's history instead: kubectl rollout undo deployment/<d>","If the Deployment is gone, recreate it or restore ownership by re-adding ownerReferences pointing at a valid controller UID","Inspect ownership first: kubectl get rs <rs> -o jsonpath='{.metadata.ownerReferences}'"],"exampleFix":"# before\nk9s rollback on orphaned replicaset my-rs  (rejected)\n\n# after\n# check ownership\nkubectl get rs my-rs -o jsonpath='{.metadata.ownerReferences}'\n# roll back the controller that owns it\nkubectl rollout undo deployment/my-deploy","handlingStrategy":"type-guard","validationCode":"rs, err := r.Load(f, fqn)\nif err != nil { return err }\nif _, _, _, cerr := controllerInfo(rs); cerr != nil {\n    return fmt.Errorf(\"rs %s is orphaned; roll back via its deployment\", rs.Name)\n}","typeGuard":"func hasController(rs *appsv1.ReplicaSet) bool {\n    for _, ref := range rs.OwnerReferences {\n        if ref.Controller != nil && *ref.Controller {\n            return true\n        }\n    }\n    return false\n}","tryCatchPattern":"if err := rsDAO.Rollback(fqn); err != nil {\n    if strings.Contains(err.Error(), \"unable to find controller for replicaset\") {\n        // no controller: fall back to manual pod-template rollback or recreate deployment\n    }\n}","preventionTips":["Avoid --cascade=orphan deletes unless you plan to adopt the orphans","Expose rollback actions only on RSs with a controller ownerReference","Keep Deployment manifests in sync so rollout undo is always available as the primary path"],"tags":["kubernetes","replicaset","owner-reference","rollback"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}