derailed/k9s · error

expecting a job runner resource for %q

Error message

expecting a job runner resource for %q

What it means

Thrown after the user confirms the 'Trigger CronJobs' dialog: k9s looks up the DAO via dao.AccessorFor(c.App().factory, c.GVR()) and type-asserts it to dao.Runnable (the interface exposing Run(fqn)). If the accessor registered for the current GVR does not implement Runnable, the assertion with ok-form fails and this error is flashed. It is an internal invariant: the trigger action is only valid on resources whose DAO can create jobs (normally the CronJob DAO).

Source

Thrown at internal/view/cronjob.go:106

func (c *CronJob) triggerCmd(evt *tcell.EventKey) *tcell.EventKey {
	fqns := c.GetTable().GetSelectedItems()
	if len(fqns) == 0 {
		return evt
	}
	msg := fmt.Sprintf("Trigger CronJob: %s?", fqns[0])
	if len(fqns) > 1 {
		msg = fmt.Sprintf("Trigger %d CronJobs?", len(fqns))
	}
	d := c.App().Styles.Dialog()
	dialog.ShowConfirm(&d, c.App().Content.Pages, "Confirm Job Trigger", msg, func() {
		res, err := dao.AccessorFor(c.App().factory, c.GVR())
		if err != nil {
			c.App().Flash().Err(fmt.Errorf("no accessor for %q", c.GVR()))
			return
		}
		runner, ok := res.(dao.Runnable)
		if !ok {
			c.App().Flash().Err(fmt.Errorf("expecting a job runner resource for %q", c.GVR()))
			return
		}

		for _, fqn := range fqns {
			if err := runner.Run(fqn); err != nil {
				c.App().Flash().Errf("CronJob trigger failed for %s: %v", fqn, err)
			} else {
				c.App().Flash().Infof("Triggered Job %s %s", c.GVR(), fqn)
			}
		}
	}, func() {})

	return nil
}

func (c *CronJob) toggleSuspendCmd(evt *tcell.EventKey) *tcell.EventKey {
	table := c.GetTable()
	sel := table.GetSelectedItem()

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Confirm you are on the stock CronJob viewer (:batch:cronjobs or :v1:cronjobs) when triggering
  2. Check views.yaml / plugin config for aliases that rebind the CronJob viewer to a different GVR
  3. Rebuild/reinstall k9s so internal/view and internal/dao come from the same release (stale mixed binaries cause this)
  4. If it reproduces on plain cronjobs with stock k9s, file an issue with the GVR string shown in the message
Defensive patterns

Strategy: type-guard

Type guard

func supportsRun(res dao.Resource) bool {
    _, ok := res.(dao.Runnable)
    return ok
}

// before showing the trigger dialog:
res, err := dao.AccessorFor(c.App().factory, c.GVR())
if err != nil || !supportsRun(res) {
    c.App().Flash().Errf("trigger is only available for runnable resources (cronjobs)")
    return
}

Prevention

When it happens

Trigger: Pressing the trigger key on the CronJob view and confirming the dialog while c.GVR() maps to a DAO that lacks a Run method — e.g. a custom plugin/CRD view that reuses the CronJob viewer, or a k9s build where the internal dao and view packages are out of sync (recompiled plugin against a different k9s version).

Common situations: Custom views (views.yaml aliases) binding the CronJob browser to another GVR; third-party plugins replacing the accessor for batch/cronjobs; version skew between a locally built k9s and vendored internal packages.

Related errors


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