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

  1. Set the key with a pointer: context.WithValue(ctx, internal.KeyGVR, gvr) where gvr is *client.GVR
  2. Verify the type at insertion sites — the assertion .(*client.GVR) must succeed
  3. 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

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


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/5d49ba3ab5f831c9. Report an issue: GitHub.