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
- Run drain from the stock node view (:nodes / :v1:nodes)
- Check views.yaml and plugins for anything rebinding the node viewer's GVR
- 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
- Expose drain only on viewers backed by the Node DAO
- Assert interfaces with the ok form and bail with a clear message instead of proceeding
- Keep node-related plugins compiled against the same k9s release
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
- node is cordoned
- expecting a switchable resource
- expecting a switchable resource
- resource is not restartable
- node is already cordoned
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/da671ce015842931.
Report an issue: GitHub.