derailed/k9s · error
expecting a controller resource for %q
Error message
expecting a controller resource for %q
What it means
internal/view/pf_extender.go's fetchPodName resolves the DAO for the viewer's GVR via dao.AccessorFor and type-asserts it to the dao.Controller interface (which provides Pod(path) to find the owning/controlled pod). If the registered accessor does not implement dao.Controller, the assertion fails and this error is returned with the GVR string. It signals that the port-forward extender was attached to a resource whose data-access object cannot map a resource path to a pod.
Source
Thrown at internal/view/pf_extender.go:102
}
pf := NewPortForward(client.PfGVR)
pf.SetContextFn(p.portForwardContext)
if err := p.App().inject(pf, false); err != nil {
p.App().Flash().Err(err)
}
return nil
}
func (p *PortForwardExtender) fetchPodName(path string) (string, error) {
res, err := dao.AccessorFor(p.App().factory, p.GVR())
if err != nil {
return "", err
}
ctrl, ok := res.(dao.Controller)
if !ok {
return "", fmt.Errorf("expecting a controller resource for %q", p.GVR())
}
return ctrl.Pod(path)
}
func (p *PortForwardExtender) portForwardContext(ctx context.Context) context.Context {
if bc := p.App().BenchFile; bc != "" {
ctx = context.WithValue(ctx, internal.KeyBenchCfg, p.App().BenchFile)
}
return context.WithValue(ctx, internal.KeyPath, p.GetTable().GetSelectedItem())
}
// ----------------------------------------------------------------------------
// Helpers...
func ensurePodPortFwdAllowed(factory dao.Factory, podName string) error {
pod, err := fetchPod(factory, podName)View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Port-forward from a viewer whose DAO implements dao.Controller (deployments, statefulsets, daemonsets, jobs, pods) instead of the failing GVR
- If this is your custom resource, implement the dao.Controller interface (Pod(path) method) on its DAO so the extender can resolve the backing pod
- Register the correct DAO in the dao registry (dao.AccessorFor must return a controller-capable accessor for that GVR)
- As a fallback, find the pod behind the resource manually (kubectl get pods --show-labels) and port-forward from the pod view
Example fix
// before: extender attached to a GVR whose DAO is generic
res, _ := dao.AccessorFor(p.App().factory, p.GVR())
ctrl, ok := res.(dao.Controller)
// ok == false -> error
// after: implement dao.Controller on the custom DAO
type MyCRD struct {
dao.Generic
}
func (d *MyCRD) Pod(path string) (string, error) {
// resolve owner -> pod name
return ownerPod(d.Factory(), path)
} Defensive patterns
Strategy: type-guard
Validate before calling
// before calling fetchPodName, verify the accessor is controller-capable
res, err := dao.AccessorFor(f, gvr)
if err != nil { return err }
if _, ok := res.(dao.Controller); !ok {
return fmt.Errorf("resource %s cannot resolve a pod; port-forward from a controller or pod view", gvr) Type guard
func asController(res dao.Resource) (dao.Controller, bool) {
c, ok := res.(dao.Controller)
return c, ok
}
// usage
if ctrl, ok := asController(res); ok {
pod, err := ctrl.Pod(path)
} Try / catch
// Go: check the comma-ok assertion instead of panicking; degrade gracefully
if ctrl, ok := res.(dao.Controller); ok {
if podName, err := ctrl.Pod(path); err == nil {
return startForward(v, podName, pts)
}
} else {
log.Debug("accessor lacks Controller", "gvr", gvr)
} Prevention
- Only attach PortForwardExtender to viewers whose DAO is known to implement dao.Controller (deploy/sts/ds/job/pod)
- Keep a compile-time interface check in custom DAOs: var _ dao.Controller = (*MyDAO)(nil)
- Run the comma-ok assertion early at viewer init and disable the pf keybinding when unsupported
When it happens
Trigger: Invoking the port-forward command (shift+f) from a viewer whose GVR's DAO is a generic/non-controller implementation — e.g. a custom resource added via k9s plugins/aliases whose accessor is dao.Generic, or any GVR registered in the DAO registry without a Pod(path) method.
Common situations: Extending k9s with custom CRD viewers and reusing PortForwardExtender on them; a k9s version bump where the dao.Controller interface gained methods a fork's custom DAO no longer satisfies; wiring the extender to a GVR that is not a pod controller (Deployment-like) by mistake.
Related errors
- expecting a ForwardRes but got %T
- no benchmark dir found in context
- no path specified in context
- expecting context GVR
- expecting context Path
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/706ba187bcdc2a41.
Report an issue: GitHub.