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 = &current
	} else {
		trueVal := true
		cj.Spec.Suspend = &trueVal
	}
	_, err = dial.BatchV1().CronJobs(ns).Update(ctx, cj, metav1.UpdateOptions{})

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Verify: kubectl auth can-i update cronjobs -n <ns> -as=you
  2. Add a Role with apiGroups: ["batch"], resources: ["cronjobs"], verbs: ["get","update"] and bind it
  3. 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

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


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