{"record":{"id":"e2516148404bac49","repo":"derailed/k9s","slug":"user-is-not-authorized-to-patch-a-deployment-e25161","errorCode":null,"errorMessage":"user is not authorized to patch a deployment","messagePattern":"user is not authorized to patch a deployment","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/pod.go","lineNumber":563,"sourceCode":"func (p *Pod) GetPodSpec(path string) (*v1.PodSpec, error) {\n\tpod, err := p.GetInstance(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpodSpec := pod.Spec\n\n\treturn &podSpec, nil\n}\n\n// SetImages sets container images.\nfunc (p *Pod) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {\n\tns, n := client.Namespaced(path)\n\tauth, err := p.Client().CanI(ns, p.gvr, n, client.PatchAccess)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !auth {\n\t\treturn fmt.Errorf(\"user is not authorized to patch a deployment\")\n\t}\n\tmanager, isManaged, err := p.isControlled(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif isManaged {\n\t\treturn fmt.Errorf(\"unable to set image. This pod is managed by %s. Please set the image on the controller\", manager)\n\t}\n\tjsonPatch, err := GetJsonPatch(imageSpecs)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdial, err := p.Client().Dial()\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = dial.CoreV1().Pods(ns).Patch(\n\t\tctx,","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/pod.go#L545-L581","documentation":"Pod.SetImages authorizes patch on the pod itself (p.gvr = pods) before building the JSON image patch. The message text says \"deployment\" — legacy wording carried over from the deployment implementation — but the check is patch on core pods in the pod's namespace.","triggerScenarios":"CanI(ns, pods, <pod>, patch) false — the user can view pods but lacks the patch verb on them.","commonSituations":"View-only users attempting set-image on a pod in k9s; environments where patch is deliberately withheld; operators fixing the wrong RBAC resource because the message says deployment.","solutions":["Grant patch on pods (not deployments): resources [\"pods\"] verbs [\"patch\"]","Verify: kubectl auth can-i patch pods -n <ns>","Read the message knowing 'deployment' is inaccurate — this code path patches core v1 pods"],"exampleFix":"apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: pod-image-patcher\n  namespace: default\nrules:\n- apiGroups: [\"\"]\n  resources: [\"pods\"]\n  verbs: [\"get\", \"patch\"]","handlingStrategy":"validation","validationCode":"ok, err := client.CanI(ns, client.PodGVR, podName, client.PatchAccess)\nif err != nil { return err }\nif !ok { return fmt.Errorf(\"patch on pods denied in %s\", ns) }","typeGuard":null,"tryCatchPattern":"if err := podDAO.SetImages(ctx, path, specs); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to patch\") {\n        // RBAC gap on pods (ignore the word 'deployment' in the message)\n    }\n}","preventionTips":["Grant patch on pods only to identities that legitimately mutate workloads","Pre-flight with kubectl auth can-i patch pods -n <ns> before exposing set-image UI","Read this DAO's messages with care — the deployment wording is historical"],"tags":["kubernetes","rbac","pod","image","patch"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}