derailed/k9s · error

user is not authorized to list nodes

Error message

user is not authorized to list nodes

What it means

FetchNode gates the read with a CanI authorization check for the get verb on the nodes resource at cluster scope and returns this error when access is denied. Note the message says "list" although the check actually performed is a get on a single named node — a wording quirk in the DAO.

Source

Thrown at internal/dao/node.go:276

	if err != nil {
		return false, err
	}

	return o.Spec.Unschedulable, nil
}

// ----------------------------------------------------------------------------
// Helpers...

// FetchNode retrieves a node.
func FetchNode(_ context.Context, f Factory, path string) (*v1.Node, error) {
	_, n := client.Namespaced(path)
	auth, err := f.Client().CanI(client.ClusterScope, client.NodeGVR, n, client.GetAccess)
	if err != nil {
		return nil, err
	}
	if !auth {
		return nil, fmt.Errorf("user is not authorized to list nodes")
	}

	o, err := f.Get(client.NodeGVR, client.FQN(client.ClusterScope, path), true, labels.Everything())
	if err != nil {
		return nil, err
	}

	var node v1.Node
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &node)
	if err != nil {
		return nil, err
	}

	return &node, nil
}

// FetchNodes retrieves all nodes.
func FetchNodes(_ context.Context, f Factory, _ string) (*v1.NodeList, error) {

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Grant node read access: a ClusterRole with apiGroups [""] resources ["nodes"] verbs ["get","list"] (or bind the built-in view ClusterRole)
  2. Verify as the same user: kubectl auth can-i get nodes
  3. Switch to a kubeconfig context with cluster read if node inspection is required

Example fix

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list"]
Defensive patterns

Strategy: validation

Validate before calling

ok, err := factory.Client().CanI(client.ClusterScope, client.NodeGVR, nodeName, client.GetAccess)
if err != nil { return err }
if !ok { return fmt.Errorf("missing get on nodes for this identity") }

Try / catch

if _, err := dao.FetchNode(ctx, f, path); err != nil {
    if strings.Contains(err.Error(), "not authorized to list nodes") {
        // terminal RBAC gap: stop and prompt for credentials/role, do not retry
    }
}

Prevention

When it happens

Trigger: CanI(cluster-scope, nodes, <name>, get) returns false — the kubeconfig user lacks the get verb on core nodes.

Common situations: Restricted service accounts (CI runners, GitOps) with only namespace-scoped roles; kubeconfig using a tenant/limited user; policy engines (OPA/Kyverno) denying node reads; users misled by the 'list' wording into granting the wrong verb.

Related errors


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