derailed/k9s · error

expecting context Path

Error message

expecting context Path

What it means

Returned by ScanForRefs (internal/dao/cluster.go:65) when ctx.Value(internal.KeyPath) is not a string. KeyPath carries the FQN of the origin resource being scanned for (the value named fqn downstream, passed to each scanner's Scan(ctx, fqn, wait)). It is checked right after KeyGVR; missing it aborts before the goroutine fan-out.

Source

Thrown at internal/dao/cluster.go:65

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)
			if err != nil {
				slog.Error("Reference scan failed for",
					slogs.RefType, fmt.Sprintf("%T", s),
					slogs.Error, err,

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Always inject KeyPath alongside KeyGVR: context.WithValue(ctx, internal.KeyPath, fqn) with fqn a plain string
  2. Centralize context construction in one helper so the three keys (GVR, Path, Wait) are never partially set
  3. Add a unit test asserting ScanForRefs succeeds with the helper-built context

Example fix

// before
ctx := context.WithValue(ctx, internal.KeyGVR, gvr)
refs, err := dao.ScanForRefs(ctx, factory)

// after
ctx = context.WithValue(ctx, internal.KeyPath, client.FQN(ns, name))
refs, err := dao.ScanForRefs(ctx, factory)
Defensive patterns

Strategy: validation

Validate before calling

if _, ok := ctx.Value(internal.KeyPath).(string); !ok {
    ctx = context.WithValue(ctx, internal.KeyPath, fqn)
}
refs, err := dao.ScanForRefs(ctx, factory)

Type guard

func hasPathKey(ctx context.Context) bool {
    _, ok := ctx.Value(internal.KeyPath).(string)
    return ok
}

Try / catch

refs, err := dao.ScanForRefs(ctx, factory)
if err != nil && strings.Contains(err.Error(), "expecting context Path") {
    ctx = context.WithValue(ctx, internal.KeyPath, fqn)
    refs, err = dao.ScanForRefs(ctx, factory)
}

Prevention

When it happens

Trigger: Calling ScanForRefs with KeyGVR set but omitting WithValue(ctx, internal.KeyPath, fqn); storing a non-string (e.g. a typed FQN struct) under the key.

Common situations: Same class as [14]: direct DAO invocation from tests/tools; context built by helper that only forwards some keys; refactor renamed the path key constant and call sites drifted.

Related errors


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