derailed/k9s · error
user is not authorized to patch a statefulset
Error message
user is not authorized to patch a statefulset
What it means
StatefulSet.SetImages first runs a SelfSubjectAccessReview (Client().CanI) for the patch verb on apps/statefulsets before issuing the patch. If the review returns not-allowed, the image update is refused client-side with this error and no request reaches the API server.
Source
Thrown at internal/dao/sts.go:230
// GetPodSpec returns a pod spec given a resource.
func (s *StatefulSet) GetPodSpec(path string) (*v1.PodSpec, error) {
sts, err := s.getStatefulSet(path)
if err != nil {
return nil, err
}
podSpec := sts.Spec.Template.Spec
return &podSpec, nil
}
// SetImages sets container images.
func (s *StatefulSet) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {
ns, n := client.Namespaced(path)
auth, err := s.Client().CanI(ns, client.StsGVR, n, client.PatchAccess)
if err != nil {
return err
}
if !auth {
return fmt.Errorf("user is not authorized to patch a statefulset")
}
jsonPatch, err := GetTemplateJsonPatch(imageSpecs)
if err != nil {
return err
}
dial, err := s.Client().Dial()
if err != nil {
return err
}
_, err = dial.AppsV1().StatefulSets(ns).Patch(
ctx,
n,
types.StrategicMergePatchType,
jsonPatch,
metav1.PatchOptions{},
)
return err
}View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Confirm the gap: kubectl auth can-i patch statefulsets.apps -n <ns> (as the same user)
- Grant the verb: add resources: [statefulsets], verbs: [patch] (or [patch, get]) to the Role/ClusterRole bound to the user
- Rebind the role with a RoleBinding in that namespace, or switch to a context/user that already has patch rights
- If you cannot get patch rights, update images by re-applying the manifest with kubectl apply/set image from an authorized account
Example fix
# before: role without patch apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-dev rules: - apiGroups: ["apps"] resources: ["statefulsets"] verbs: ["get", "list"] # after: patch granted apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-dev rules: - apiGroups: ["apps"] resources: ["statefulsets"] verbs: ["get", "list", "patch"]
Defensive patterns
Strategy: validation
Validate before calling
allowed, err := k8sClient.CanI(ns, client.StsGVR, name, client.PatchAccess)
if err != nil { return err }
if !allowed {
return fmt.Errorf("missing patch on statefulsets.apps in %s — run: kubectl auth can-i patch statefulsets -n %s", ns, ns)
} Try / catch
if err := stsDAO.SetImages(ctx, path, specs); err != nil {
if strings.Contains(err.Error(), "not authorized") {
// guide user to RBAC fix instead of retrying blindly
return showRbacHint("patch", "statefulsets.apps", ns)
}
return err
} Prevention
- Pre-check with kubectl auth can-i patch statefulsets -n <ns> when switching contexts/users
- Hide or grey out image-swap actions when the self-access review denies patch
- Keep RBAC bindings for CI/viewer accounts minimal but include patch where image updates are expected
When it happens
Trigger: Calling SetImages (e.g. using the image-swap/edit-image action on a StatefulSet in k9s) with a kubeconfig user bound to a Role/ClusterRole lacking the patch verb on statefulsets.apps in that namespace.
Common situations: Read-only viewer accounts, CI service accounts, or restricted RBAC in shared clusters; assuming a different (under-privileged) user via k9s impersonation flags; kubeconfig contexts pointing at a token with minimal scopes.
Related errors
- user is not authorized to run jobs
- user is not authorized to (un)suspend cronjobs
- user is not authorized to patch a deployment
- user is not authorized to scale: %s
- user is not authorized to restart %q
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/13da25648342a4ec.
Report an issue: GitHub.