{"record":{"id":"5d49ba3ab5f831c9","repo":"derailed/k9s","slug":"expecting-context-gvr","errorCode":null,"errorMessage":"expecting context GVR","messagePattern":"expecting context GVR","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/cluster.go","lineNumber":61,"sourceCode":"\t_ RefScanner = (*Job)(nil)\n\t_ RefScanner = (*CronJob)(nil)\n)\n\nfunc scanners() map[*client.GVR]RefScanner {\n\treturn map[*client.GVR]RefScanner{\n\t\tclient.DpGVR:  new(Deployment),\n\t\tclient.DsGVR:  new(DaemonSet),\n\t\tclient.StsGVR: new(StatefulSet),\n\t\tclient.CjGVR:  new(CronJob),\n\t\tclient.JobGVR: new(Job),\n\t}\n}\n\n// ScanForRefs scans cluster resources for resource references.\nfunc ScanForRefs(ctx context.Context, f Factory) (Refs, error) {\n\trgvr, ok := ctx.Value(internal.KeyGVR).(*client.GVR)\n\tif !ok {\n\t\treturn nil, errors.New(\"expecting context GVR\")\n\t}\n\tfqn, ok := ctx.Value(internal.KeyPath).(string)\n\tif !ok {\n\t\treturn nil, errors.New(\"expecting context Path\")\n\t}\n\twait, ok := ctx.Value(internal.KeyWait).(bool)\n\tif !ok {\n\t\tslog.Warn(\"Expecting context Wait key. Using default\")\n\t}\n\n\tvar wg sync.WaitGroup\n\tout := make(chan Refs)\n\tfor gvr, scanner := range scanners() {\n\t\twg.Add(1)\n\t\tgo func(ctx context.Context, gvr *client.GVR, s RefScanner, out chan Refs, wait bool) {\n\t\t\tdefer wg.Done()\n\t\t\ts.Init(f, gvr)\n\t\t\trefs, err := s.Scan(ctx, rgvr, fqn, wait)","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/cluster.go#L43-L79","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nrefs, err := dao.ScanForRefs(context.Background(), factory)\n\n// after\nctx := context.WithValue(ctx, internal.KeyGVR, gvr)   // *client.GVR\nctx = context.WithValue(ctx, internal.KeyPath, fqn)\nrefs, err := dao.ScanForRefs(ctx, factory)","handlingStrategy":"validation","validationCode":"func refsCtx(ctx context.Context, gvr *client.GVR, fqn string, wait bool) context.Context {\n    ctx = context.WithValue(ctx, internal.KeyGVR, gvr)\n    ctx = context.WithValue(ctx, internal.KeyPath, fqn)\n    return context.WithValue(ctx, internal.KeyWait, wait)\n}","typeGuard":"func hasGVRKey(ctx context.Context) bool {\n    _, ok := ctx.Value(internal.KeyGVR).(*client.GVR)\n    return ok\n}","tryCatchPattern":"refs, err := dao.ScanForRefs(ctx, factory)\nif err != nil && strings.Contains(err.Error(), \"expecting context GVR\") {\n    // rebuild ctx with all three keys and retry\n}","preventionTips":["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"],"tags":["go","context","k9s","references","dao"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}