derailed/k9s · error

user is not authorized to run jobs

Error message

user is not authorized to run jobs

What it means

CronJob.Run (internal/dao/cronjob.go:48-57) triggers a CronJob by creating a Job from its template. Before doing so it asks SelfSubjectAccessReview (client.CanI) for get AND create on jobs.batch in the target namespace; if either is denied it returns this error without touching the cluster.

Source

Thrown at internal/dao/cronjob.go:54

// ListImages lists container images.
func (c *CronJob) ListImages(_ context.Context, fqn string) ([]string, error) {
	cj, err := c.GetInstance(fqn)
	if err != nil {
		return nil, err
	}

	return render.ExtractImages(&cj.Spec.JobTemplate.Spec.Template.Spec), nil
}

// Run a CronJob.
func (c *CronJob) Run(path string) error {
	ns, n := client.Namespaced(path)
	auth, err := c.Client().CanI(ns, client.JobGVR, n, []string{client.GetVerb, client.CreateVerb})
	if err != nil {
		return err
	}
	if !auth {
		return fmt.Errorf("user is not authorized to run jobs")
	}

	o, err := c.getFactory().Get(c.gvr, path, true, labels.Everything())
	if err != nil {
		return err
	}
	var cj batchv1.CronJob
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &cj)
	if err != nil {
		return errors.New("expecting CronJob resource")
	}
	jobName := cj.Name
	if len(cj.Name) >= maxJobNameSize {
		jobName = cj.Name[0:maxJobNameSize]
	}
	trueVal := true
	job := &batchv1.Job{
		ObjectMeta: metav1.ObjectMeta{

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Check what you lack: kubectl auth can-i create jobs -n <ns> and kubectl auth can-i get jobs -n <ns>
  2. Grant both verbs in a Role + RoleBinding, e.g. rules: - apiGroups: ["batch"] resources: ["jobs"] verbs: ["get","create"]
  3. Or run k9s with a context/user that already has the permission
  4. If you only meant to inspect the CronJob, use describe/view instead of trigger
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight the exact SSAR check Run uses before offering the trigger action.
func CanTrigger(c client.Client, ns string) (bool, error) {
	return c.CanI(ns, client.JobGVR, "", []string{client.GetVerb, client.CreateVerb})
}

Try / catch

if err := cj.Run(path); err != nil {
    if strings.Contains(err.Error(), "not authorized to run jobs") {
        log.Printf("trigger blocked by RBAC: grant get+create on jobs.batch in %s", ns)
    }
    return err
}

Prevention

When it happens

Trigger: Invoking the k9s trigger/run action on a CronJob while the current kubeconfig user or service account lacks `get jobs` or `create jobs` in that namespace. The check is namespace- and verb-specific; ownership of the CronJob itself is irrelevant.

Common situations: View-only RBAC roles (granted get/list on everything but no create); CI service accounts used with k9s; restricted namespaces where developers may inspect cronjobs but only a pipeline may fire them.

Related errors


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