derailed/k9s · error
expecting a factory but got %T
Error message
expecting a factory but got %T
What it means
locatePods (internal/xray/svc.go:77) pulls the DAO factory from the render context (ctx.Value(internal.KeyFactory)) and asserts it to dao.Factory. The error means the xray render context was created without the factory installed — the traversal entry point normally injects it — so pod listing by service selector cannot proceed.
Source
Thrown at internal/xray/svc.go:77
if root.IsLeaf() {
return nil
}
gvr, nsID := client.NsGVR, client.FQN(client.ClusterScope, svc.Namespace)
nsn := parent.Find(gvr, nsID)
if nsn == nil {
nsn = NewTreeNode(gvr, nsID)
parent.Add(nsn)
}
nsn.Add(root)
return nil
}
func (s *Service) locatePods(ctx context.Context, ns string, sel map[string]string) ([]runtime.Object, error) {
f, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
if !ok {
return nil, fmt.Errorf("expecting a factory but got %T", ctx.Value(internal.KeyFactory))
}
ll := make([]string, 0, len(sel))
for k, v := range sel {
ll = append(ll, fmt.Sprintf("%s=%s", k, v))
}
fsel, err := labels.ConvertSelectorToLabelsMap(strings.Join(ll, ","))
if err != nil {
return nil, err
}
return f.List(client.PodGVR, ns, false, fsel.AsSelector())
}
View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Inject the factory before rendering: ctx = context.WithValue(ctx, internal.KeyFactory, app.factory) at the top of the xray traversal
- In tests, pass the real or fake dao.Factory: ctx = context.WithValue(context.Background(), internal.KeyFactory, factory)
- Keep the whole render chain on the same derived context so the value survives recursion
- Read the %T in the message to confirm what (if anything) replaced the factory value
Example fix
// before ctx := context.Background() s.Render(ctx, "ns1", obj) // -> expecting a factory but got <nil> // after ctx := context.WithValue(context.Background(), internal.KeyFactory, app.factory) s.Render(ctx, "ns1", obj)
Defensive patterns
Strategy: type-guard
Validate before calling
// verify the factory is in the context before listing pods
f, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
if !ok {
return nil, fmt.Errorf("xray requires internal.KeyFactory in the context; got %T", ctx.Value(internal.KeyFactory))
} Type guard
func factoryFrom(ctx context.Context) (dao.Factory, bool) {
f, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
return f, ok
} Prevention
- Inject the factory once at the top of the xray traversal: context.WithValue(ctx, internal.KeyFactory, factory)
- Pass the same derived context down the whole render chain
- In tests, seed internal.KeyFactory with a real or fake dao.Factory before rendering
When it happens
Trigger: Calling a renderer that calls locatePods with a context not built by the xray command (context.Background() or a context missing internal.KeyFactory); refactors that drop the context.WithValue(ctx, internal.KeyFactory, factory) at traversal start.
Common situations: Custom xray renderers or extracted helper code reused outside the xray flow; unit tests constructing contexts by hand; refactors losing the KeyFactory injection.
Related errors
- expecting a TreeNode 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/6d4bafd95bee9728.
Report an issue: GitHub.