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
- Confirm you are on the stock CronJob viewer (:batch:cronjobs or :v1:cronjobs) when triggering
- Check views.yaml / plugin config for aliases that rebind the CronJob viewer to a different GVR
- Rebuild/reinstall k9s so internal/view and internal/dao come from the same release (stale mixed binaries cause this)
- 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
- Only bind the CronJob viewer/trigger action to GVRs whose DAO implements dao.Runnable
- When writing plugins, type-assert accessors with the ok form and degrade gracefully instead of assuming the interface
- Keep internal dao and view packages from the same k9s release when building from source
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
- expecting a switchable resource
- expecting a switchable resource
- resource is not restartable
- expecting a ContainsPodSpec for %q but got %T
- expecting a nuker for %q
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/d6491879f94618c5.
Report an issue: GitHub.