derailed/k9s · error
user is not authorized to (un)suspend cronjobs
Error message
user is not authorized to (un)suspend cronjobs
What it means
CronJob.ToggleSuspend (internal/dao/cronjob.go:144-155) flips spec.suspend on a CronJob. It first requires get AND update on cronjobs.batch in the namespace (client.CanI); a denial returns this error before any API dial.
Source
Thrown at internal/dao/cronjob.go:151
var cj batchv1.CronJob
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &cj)
if err != nil {
return nil, errors.New("expecting cronjob resource")
}
return &cj, nil
}
// ToggleSuspend toggles suspend/resume on a CronJob.
func (c *CronJob) ToggleSuspend(ctx context.Context, path string) error {
ns, n := client.Namespaced(path)
auth, err := c.Client().CanI(ns, c.gvr, n, []string{client.GetVerb, client.UpdateVerb})
if err != nil {
return err
}
if !auth {
return fmt.Errorf("user is not authorized to (un)suspend cronjobs")
}
dial, err := c.Client().Dial()
if err != nil {
return err
}
cj, err := dial.BatchV1().CronJobs(ns).Get(ctx, n, metav1.GetOptions{})
if err != nil {
return err
}
if cj.Spec.Suspend != nil {
current := !*cj.Spec.Suspend
cj.Spec.Suspend = ¤t
} else {
trueVal := true
cj.Spec.Suspend = &trueVal
}
_, err = dial.BatchV1().CronJobs(ns).Update(ctx, cj, metav1.UpdateOptions{})View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Verify: kubectl auth can-i update cronjobs -n <ns> -as=you
- Add a Role with apiGroups: ["batch"], resources: ["cronjobs"], verbs: ["get","update"] and bind it
- Or patch through a permitted channel (GitOps PR changing spec.suspend) instead of k9s
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight the suspend toggle's requirement: get+update on cronjobs.
func CanToggle(c client.Client, ns string) (bool, error) {
return c.CanI(ns, client.CronJobGVR, "", []string{client.GetVerb, client.UpdateVerb})
} Try / catch
if err := cj.ToggleSuspend(ctx, path); err != nil {
if strings.Contains(err.Error(), "not authorized to (un)suspend") {
// surface an actionable hint instead of a raw failure
return fmt.Errorf("need get+update on cronjobs.batch in %s (kubectl auth can-i update cronjobs -n %s)", ns, ns)
}
return err
} Prevention
- Grant [get, update] on cronjobs.batch to on-call roles that must pause schedules
- Prefer GitOps PRs for suspend changes in locked-down clusters
When it happens
Trigger: Invoking suspend/unsuspend on a CronJob when the authenticated identity lacks either `get cronjobs` or `update cronjobs` (or patch, which RBAC-wise is covered separately - here update is the required verb) in the CronJob's namespace.
Common situations: On-call operators with read-only access trying to pause a noisy CronJob; multi-tenant namespaces where only a deployer role may mutate workloads; kubeconfig pointing at the wrong user after a token rotation.
Related errors
- user is not authorized to run jobs
- user is not authorized to patch a deployment
- user is not authorized to scale: %s
- user is not authorized to restart %q
- user is not authorized to delete %s
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/60b8426f14c1bc75.
Report an issue: GitHub.