{"record":{"id":"c4c77c2006938cc6","repo":"derailed/k9s","slug":"custom-column-resolution-error","errorCode":null,"errorMessage":"custom column resolution error","messagePattern":"custom column resolution error","errorType":"exception","errorClass":"ErrCustomColumn","httpStatus":null,"severity":"warning","filePath":"internal/model1/helpers.go","lineNumber":23,"sourceCode":"\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log/slog\"\n\t\"math\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/derailed/k9s/internal/slogs\"\n\t\"github.com/fvbommel/sortorder\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\tk8sruntime \"k8s.io/apimachinery/pkg/runtime\"\n)\n\nvar ErrCustomColumn = errors.New(\"custom column resolution error\")\n\n// parallelRender fans work across NumCPU batch workers.\nfunc parallelRender(n int, fn func(i int) error) error {\n\tif n == 0 {\n\t\treturn nil\n\t}\n\n\tworkers := min(runtime.NumCPU(), n)\n\tif workers < 1 {\n\t\tworkers = 1\n\t}\n\tchunkSize := (n + workers - 1) / workers\n\n\tvar (\n\t\twg       sync.WaitGroup\n\t\tfirstErr error\n\t\terrOnce  sync.Once\n\t)","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/model1/helpers.go#L5-L41","documentation":"ErrCustomColumn is a sentinel declared in model1/helpers.go and wrapped by the custom-column renderer (render/cust_cols.go:209) as fmt.Errorf(\"%w: %q: %w\", ErrCustomColumn, columnName, err). It means a user-defined column in views.yaml/columns config has a JSONPath expression that failed to resolve against the resource. helpers.go:85 and cust_cols_test.go:295 match it with errors.Is.","triggerScenarios":"A custom column whose path does not exist on the object (typo like $.spec.repica), syntactically invalid JSONPath, or a path valid for one GVR applied to another; rendering fails per column and the errors are joined.","commonSituations":"Editing views.yaml to add columns against evolving CRD schemas; copying column configs between resources with different shapes; k8s version changes renaming fields (e.g. deprecated fields removed).","solutions":["Check the wrapped message: it names the offending column header and the underlying path error — fix that path in your views.yaml.","Validate the JSONPath against a live object: kubectl get <res> -o jsonpath='<your-path>'.","Keep per-GVR column definitions scoped to the resource they were written for."],"exampleFix":"# before (views.yaml)\ncolumns:\n  - name: REPLICAS\n    path: .spec.repicas   # typo\n# after\ncolumns:\n  - name: REPLICAS\n    path: .spec.replicas","handlingStrategy":"validation","validationCode":"// validate a custom column path against a live object before adding it\nfunc pathResolves(path string, o map[string]any) bool {\n    r, err := jsonpath.New(\"col\")\n    if err != nil { return false }\n    if err := r.Parse(path); err != nil { return false }\n    return true\n}","typeGuard":"func isCustomColumnErr(err error) bool { return errors.Is(err, model1.ErrCustomColumn) }","tryCatchPattern":"err := renderer.Render(row, o)\nif errors.Is(err, model1.ErrCustomColumn) {\n    // message names the column; fix its path in views.yaml and re-render\n}","preventionTips":["Test JSONPath expressions with kubectl -o jsonpath before committing views.yaml.","Scope custom columns to the GVR whose schema you verified.","Re-validate column configs after CRD upgrades."],"tags":["go","kubernetes","jsonpath","custom-columns","config"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}