{"record":{"id":"bd2ac31a8682a377","repo":"derailed/k9s","slug":"user-is-not-authorized-to-delete-s","errorCode":null,"errorMessage":"user is not authorized to delete %s","messagePattern":"user is not authorized to delete (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/generic.go","lineNumber":117,"sourceCode":"\t\treturn \"\", err\n\t}\n\n\traw, err := ToYAML(o, showManaged)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to marshal resource %w\", err)\n\t}\n\treturn raw, nil\n}\n\n// Delete deletes a resource.\nfunc (g *Generic) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, grace Grace) error {\n\tns, n := client.Namespaced(path)\n\tauth, err := g.Client().CanI(ns, g.gvr, n, []string{client.DeleteVerb})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !auth {\n\t\treturn fmt.Errorf(\"user is not authorized to delete %s\", path)\n\t}\n\n\tvar gracePeriod *int64\n\tif grace != DefaultGrace {\n\t\tgracePeriod = (*int64)(&grace)\n\t}\n\topts := metav1.DeleteOptions{\n\t\tPropagationPolicy:  propagation,\n\t\tGracePeriodSeconds: gracePeriod,\n\t}\n\n\tdial, err := g.dynClient()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif client.IsClusterScoped(ns) {\n\t\treturn dial.Delete(ctx, n, opts)\n\t}","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/generic.go#L99-L135","documentation":"Generic.Delete (internal/dao/generic.go:108-119) performs authorization before destruction: it requires the delete verb on the resource's GVR in its namespace (client.CanI). Denial returns this error printing the resource path (namespace/name - the message does not include the GVR kind).","triggerScenarios":"Pressing ctrl-d / delete on any resource while the identity lacks `delete` on that resource type in that namespace. Grace period and propagation options are irrelevant - the call is blocked before any API request.","commonSituations":"View-only auditors in production namespaces; namespaces where deletion is reserved to a CI service account; users forgetting k9s is bound to a privileged context and testing RBAC restrictions.","solutions":["Verify: kubectl auth can-i delete <resource> -n <ns>","Grant verbs: [\"delete\"] on the resource in a Role and bind it, or escalate to the break-glass identity","Use namespace deletion or a pipeline with sufficient permission if per-object delete is locked"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-flight the delete verb before showing/enabling the delete action.\nfunc CanDelete(c client.Client, gvr *client.GVR, ns, n string) (bool, error) {\n\treturn c.CanI(ns, gvr, n, []string{client.DeleteVerb})\n}","typeGuard":null,"tryCatchPattern":"if err := g.Delete(ctx, path, propagation, grace); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to delete\") {\n        return fmt.Errorf(\"RBAC: grant verbs:[delete] on %s in namespace %s (kubectl auth can-i delete %s -n %s)\", g.gvr, ns, g.gvr, ns)\n    }\n    return err\n}","preventionTips":["Run the SSAR pre-check per GVR before enabling destructive keybindings","Scope delete roles per namespace instead of cluster-wide","Log path+GVR on denial - the runtime message only carries the path"],"tags":["go","kubernetes","rbac","k9s","delete","authorization"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}