derailed/k9s · error
expecting context GVR
Error message
expecting context GVR
What it means
Returned by ScanForRefs (internal/dao/cluster.go:61) when ctx.Value(internal.KeyGVR) is not a *client.GVR. This function powers k9s reference scanning (which workloads reference a given resource, e.g. a ConfigMap/Secret); it fans out goroutines per scanner GVR (Deployments, DaemonSets, StatefulSets, CronJobs, Jobs) and needs the origin resource's GVR from context. A missing or wrongly-typed value aborts the whole scan.
Source
Thrown at internal/dao/cluster.go:61
_ RefScanner = (*Job)(nil)
_ RefScanner = (*CronJob)(nil)
)
func scanners() map[*client.GVR]RefScanner {
return map[*client.GVR]RefScanner{
client.DpGVR: new(Deployment),
client.DsGVR: new(DaemonSet),
client.StsGVR: new(StatefulSet),
client.CjGVR: new(CronJob),
client.JobGVR: new(Job),
}
}
// ScanForRefs scans cluster resources for resource references.
func ScanForRefs(ctx context.Context, f Factory) (Refs, error) {
rgvr, ok := ctx.Value(internal.KeyGVR).(*client.GVR)
if !ok {
return nil, errors.New("expecting context GVR")
}
fqn, ok := ctx.Value(internal.KeyPath).(string)
if !ok {
return nil, errors.New("expecting context Path")
}
wait, ok := ctx.Value(internal.KeyWait).(bool)
if !ok {
slog.Warn("Expecting context Wait key. Using default")
}
var wg sync.WaitGroup
out := make(chan Refs)
for gvr, scanner := range scanners() {
wg.Add(1)
go func(ctx context.Context, gvr *client.GVR, s RefScanner, out chan Refs, wait bool) {
defer wg.Done()
s.Init(f, gvr)
refs, err := s.Scan(ctx, rgvr, fqn, wait)View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Set the key with a pointer: context.WithValue(ctx, internal.KeyGVR, gvr) where gvr is *client.GVR
- Verify the type at insertion sites — the assertion .(*client.GVR) must succeed
- Prefer the higher-level entry points (the view that launches ref scans) that already assemble KeyGVR, KeyPath and KeyWait
Example fix
// before refs, err := dao.ScanForRefs(context.Background(), factory) // after ctx := context.WithValue(ctx, internal.KeyGVR, gvr) // *client.GVR ctx = context.WithValue(ctx, internal.KeyPath, fqn) refs, err := dao.ScanForRefs(ctx, factory)
Defensive patterns
Strategy: validation
Validate before calling
func refsCtx(ctx context.Context, gvr *client.GVR, fqn string, wait bool) context.Context {
ctx = context.WithValue(ctx, internal.KeyGVR, gvr)
ctx = context.WithValue(ctx, internal.KeyPath, fqn)
return context.WithValue(ctx, internal.KeyWait, wait)
} Type guard
func hasGVRKey(ctx context.Context) bool {
_, ok := ctx.Value(internal.KeyGVR).(*client.GVR)
return ok
} Try / catch
refs, err := dao.ScanForRefs(ctx, factory)
if err != nil && strings.Contains(err.Error(), "expecting context GVR") {
// rebuild ctx with all three keys and retry
} Prevention
- Construct scan contexts via a single helper so GVR/Path/Wait are always set
- Store *client.GVR (pointer) — the type assertion requires it
- Unit-test the helper-built context against ScanForRefs
When it happens
Trigger: Invoking ScanForRefs(ctx, factory) with a context that never had WithValue(ctx, internal.KeyGVR, gvr) applied, or where the stored value is a client.GVR (value, not pointer) or another type.
Common situations: Custom tooling or tests calling the ref-scan directly; refactors changing the stored type from *GVR to GVR; calling with context.Background() out of convenience.
Related errors
- expecting context Path
- no benchmark dir found in context
- no path specified in context
- expecting context Wait
- no dir in context
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/5d49ba3ab5f831c9.
Report an issue: GitHub.