derailed/k9s · warning · ErrCustomColumn

custom column resolution error

Error message

custom column resolution error

What it means

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.

Source

Thrown at internal/model1/helpers.go:23

import (
	"errors"
	"fmt"
	"log/slog"
	"math"
	"runtime"
	"sort"
	"strings"
	"sync"

	"github.com/derailed/k9s/internal/slogs"
	"github.com/fvbommel/sortorder"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8sruntime "k8s.io/apimachinery/pkg/runtime"
)

var ErrCustomColumn = errors.New("custom column resolution error")

// parallelRender fans work across NumCPU batch workers.
func parallelRender(n int, fn func(i int) error) error {
	if n == 0 {
		return nil
	}

	workers := min(runtime.NumCPU(), n)
	if workers < 1 {
		workers = 1
	}
	chunkSize := (n + workers - 1) / workers

	var (
		wg       sync.WaitGroup
		firstErr error
		errOnce  sync.Once
	)

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Check the wrapped message: it names the offending column header and the underlying path error — fix that path in your views.yaml.
  2. Validate the JSONPath against a live object: kubectl get <res> -o jsonpath='<your-path>'.
  3. Keep per-GVR column definitions scoped to the resource they were written for.

Example fix

# before (views.yaml)
columns:
  - name: REPLICAS
    path: .spec.repicas   # typo
# after
columns:
  - name: REPLICAS
    path: .spec.replicas
Defensive patterns

Strategy: validation

Validate before calling

// validate a custom column path against a live object before adding it
func pathResolves(path string, o map[string]any) bool {
    r, err := jsonpath.New("col")
    if err != nil { return false }
    if err := r.Parse(path); err != nil { return false }
    return true
}

Type guard

func isCustomColumnErr(err error) bool { return errors.Is(err, model1.ErrCustomColumn) }

Try / catch

err := renderer.Render(row, o)
if errors.Is(err, model1.ErrCustomColumn) {
    // message names the column; fix its path in views.yaml and re-render
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


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