derailed/k9s · error

user is not authorized to delete %s

Error message

user is not authorized to delete %s

What it means

Workload.Delete runs a SelfSubjectAccessReview (Client().CanI) for the delete verb on the workload's GVR before issuing the delete. If the review says not-allowed, the delete is refused client-side and the API server is never called.

Source

Thrown at internal/dao/workload.go:51

	client.StsGVR,
	client.DpGVR,
	client.RsGVR,
}

// Workload tracks a select set of resources in a given namespace.
type Workload struct {
	Table
}

func (w *Workload) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, grace Grace) error {
	gvr, _ := ctx.Value(internal.KeyGVR).(*client.GVR)
	ns, n := client.Namespaced(path)
	auth, err := w.Client().CanI(ns, gvr, n, []string{client.DeleteVerb})
	if err != nil {
		return err
	}
	if !auth {
		return fmt.Errorf("user is not authorized to delete %s", path)
	}

	var gracePeriod *int64
	if grace != DefaultGrace {
		gracePeriod = (*int64)(&grace)
	}
	opts := metav1.DeleteOptions{
		PropagationPolicy:  propagation,
		GracePeriodSeconds: gracePeriod,
	}

	ctx, cancel := context.WithTimeout(ctx, w.Client().Config().CallTimeout())
	defer cancel()

	d, err := w.Client().DynDial()
	if err != nil {
		return err
	}

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Confirm with kubectl auth can-i delete <resource>.<group> -n <ns> (same user)
  2. Add verbs: ["delete"] (and deletecollection if bulk deletes are needed) for that resource to the bound Role/ClusterRole
  3. Apply the RoleBinding or switch context to a user with delete rights
  4. If RBAC cannot change, delete from an authorized context: kubectl delete <resource> <name> -n <ns>

Example fix

# before
verbs: ["get", "list", "watch"]
# after
verbs: ["get", "list", "watch", "delete"]
Defensive patterns

Strategy: validation

Validate before calling

allowed, err := k8sClient.CanI(ns, gvr, name, []string{"delete"})
if err != nil { return err }
if !allowed {
    return fmt.Errorf("missing delete on %s in %s — grant it or use an authorized context", gvr, ns)
}

Try / catch

if err := w.Delete(ctx, path, propagation, grace); err != nil {
    if strings.Contains(err.Error(), "not authorized to delete") {
        return confirmAndRetryWithPrivilegedContext(path) // or abort with an RBAC hint
    }
    return err
}

Prevention

When it happens

Trigger: Deleting any workload through Workload.Delete with a kubeconfig user whose Role/ClusterRole lacks the delete verb for that resource in that namespace (e.g. view-only roles, CI tokens, impersonated under-privileged users).

Common situations: Read-only viewer bindings in production clusters; service accounts used by pipelines that can list but not delete; assuming a restricted identity via k9s --as-user flag.

Related errors


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/969bfbb630222da0. Report an issue: GitHub.