{"record":{"id":"4214d7a7d5527839","repo":"derailed/k9s","slug":"failed-to-fetch-source-resource-w","errorCode":null,"errorMessage":"failed to fetch source resource: %w","messagePattern":"failed to fetch source resource: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/view/custom_jump.go","lineNumber":28,"sourceCode":"\t\"log/slog\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/derailed/k9s/internal\"\n\t\"github.com/derailed/k9s/internal/client\"\n\t\"github.com/derailed/k9s/internal/config\"\n\t\"github.com/derailed/k9s/internal/dao\"\n\t\"github.com/derailed/k9s/internal/slogs\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n)\n\n// customJump handles custom jumps between CRDs based on user configuration.\nfunc customJump(app *App, sourceGVR *client.GVR, sourcePath string, rule *config.JumpRule) error {\n\t// Get the source resource to extract metadata for templating\n\tsourceObj, err := fetchResourceObject(app, sourceGVR, sourcePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch source resource: %w\", err)\n\t}\n\n\t// Parse target GVR\n\ttargetGVR := client.NewGVR(rule.TargetGVR)\n\n\t// Determine target namespace\n\ttargetNS, err := determineTargetNamespace(sourcePath, rule.TargetNamespace, sourceObj)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Use the registered viewer so built-in enter-chains (e.g. deploy -> pods -> logs) still work.\n\tvar v ResourceViewer\n\tif mv, ok := customViewers[targetGVR]; ok {\n\t\tif mv.viewerFn != nil {\n\t\t\tv = mv.viewerFn(targetGVR)\n\t\t} else {\n\t\t\tv = NewBrowser(targetGVR)","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/view/custom_jump.go#L10-L46","documentation":"customJump() first calls fetchResourceObject() to load the source object's full metadata for templating; this error wraps whatever failed inside (no accessor for the source GVR, or accessor.Get returning an API error such as NotFound or a 5xx). The %w keeps the underlying cause, so the real reason is appended to this message.","triggerScenarios":"Invoking a custom jump rule when the source row is stale (the object was deleted between listing and the jump), the GET against the API server fails, or the source GVR has no registered DAO.","commonSituations":"Resource deleted right before the jump (long-lived list view); RBAC denying get on the source resource; flaky API server / VPN drop; jump rule configured with a source that is not discoverable.","solutions":["Refresh the view and retry the jump so the row references a live object","Read the wrapped cause: 'not found' means the object is gone; 403 means RBAC; connection errors mean cluster reachability","Confirm the object with kubectl get <gvr> <path> using the same context"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// optional preflight: confirm the source row still exists before jumping\nif _, err := fetchResourceObject(app, sourceGVR, sourcePath); err != nil {\n    app.Flash().Errf(\"source object %s is gone or unreadable: %v\", sourcePath, err)\n    return\n}","typeGuard":null,"tryCatchPattern":"err := customJump(app, gvr, path, rule)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to fetch source resource\") {\n        // surface the wrapped cause: NotFound -> stale row, 403 -> RBAC, else connectivity\n        app.Flash().Errf(\"jump aborted: %v\", errors.Unwrap(err))\n    }\n}","preventionTips":["Refresh list views before acting on rows that may be stale","Verify RBAC grants get on jump source resources","Read the wrapped cause — this error is always a wrapper; the real reason is the %w payload"],"tags":["kubernetes","k9s","custom-resource","jump","api-error"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}