derailed/k9s · error

expecting a maintainer for %q

Error message

expecting a maintainer for %q

What it means

drainNode() fetches the accessor for the viewer's GVR and asserts it to dao.NodeMaintainer (the Drain-capable interface implemented by the Node DAO). Failure means the current GVR is not backed by the Node DAO, so draining is impossible — an invariant break rather than a cluster problem (a real drain failure would come from m.Drain instead).

Source

Thrown at internal/view/node.go:117

	opts := dao.DrainOptions{
		GracePeriodSeconds: -1,
		Timeout:            5 * time.Second,
	}
	ShowDrain(n, sels, opts, drainNode)

	return nil
}

func drainNode(v ResourceViewer, sels []string, opts dao.DrainOptions) {
	res, err := dao.AccessorFor(v.App().factory, v.GVR())
	if err != nil {
		v.App().Flash().Err(err)
		return
	}
	m, ok := res.(dao.NodeMaintainer)
	if !ok {
		v.App().Flash().Err(fmt.Errorf("expecting a maintainer for %q", v.GVR()))
		return
	}

	v.Stop()
	defer v.Start()
	{
		d := NewDetails(v.App(), "Drain Progress", "nodes", contentYAML, true)
		if err := v.App().inject(d, false); err != nil {
			v.App().Flash().Err(err)
		}
		for _, sel := range sels {
			if err := m.Drain(sel, opts, d.GetWriter()); err != nil {
				v.App().Flash().Err(err)
			}
		}
		v.Refresh()
	}
}

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Run drain from the stock node view (:nodes / :v1:nodes)
  2. Check views.yaml and plugins for anything rebinding the node viewer's GVR
  3. Reinstall/upgrade k9s cleanly so view and dao packages match
Defensive patterns

Strategy: type-guard

Type guard

func isNodeMaintainer(res dao.Resource) (dao.NodeMaintainer, bool) {
    m, ok := res.(dao.NodeMaintainer)
    return m, ok
}

if m, ok := isNodeMaintainer(res); !ok {
    v.App().Flash().Errf("drain unsupported for %q", v.GVR())
    return
} else {
    defer func() { _ = m.Drain(sel, opts, w) }()
}

Prevention

When it happens

Trigger: Invoking drain/cordon-adjacent actions while the viewer's GVR resolves to a non-Node DAO — a plugin or custom view rebinding the node viewer, or accessor registration skew after mixing k9s versions.

Common situations: Custom plugins wrapping the node view; k9s upgraded in place leaving stale compiled-in registrations; aliased GVRs for node-like CRDs using the node viewer.

Related errors


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