derailed/k9s · error

user is not authorized to list node metrics

Error message

user is not authorized to list node metrics

What it means

Raised at internal/client/metrics.go:100 inside checkAccess when the RBAC check for the node-metrics GVR (nodes.metrics.k8s.io, checked at ClusterScope) returns auth=false. The message is the caller-supplied const in FetchNodesMetrics (metrics.go:152) and FetchNodeMetrics (:194). It means the user is connected and metrics-server exists, but lacks the list verb on nodes.metrics.k8s.io.

Source

Thrown at internal/client/metrics.go:100

		tcpu += mx.AllocatableCPU
		tmem += mx.AllocatableMEM
	}
	mx.PercCPU, mx.PercMEM = ToPercentage(ccpu, tcpu), ToPercentage(cmem, tmem)

	return nil
}

func (m *MetricsServer) checkAccess(ns string, gvr *GVR, msg string) error {
	if !m.HasMetrics() {
		return errors.New("no metrics-server detected on cluster")
	}

	auth, err := m.CanI(ns, gvr, "", ListAccess)
	if err != nil {
		return err
	}
	if !auth {
		return errors.New(msg)
	}
	return nil
}

// NodesMetrics retrieves metrics for a given set of nodes.
func (*MetricsServer) NodesMetrics(nodes *v1.NodeList, metrics *mv1beta1.NodeMetricsList, mmx NodesMetrics) {
	if nodes == nil || metrics == nil {
		return
	}

	for i := range nodes.Items {
		mmx[nodes.Items[i].Name] = NodeMetrics{
			AllocatableCPU:       nodes.Items[i].Status.Allocatable.Cpu().MilliValue(),
			AllocatableMEM:       ToMB(nodes.Items[i].Status.Allocatable.Memory().Value()),
			AllocatableEphemeral: ToMB(nodes.Items[i].Status.Allocatable.StorageEphemeral().Value()),
			TotalCPU:             nodes.Items[i].Status.Capacity.Cpu().MilliValue(),
			TotalMEM:             ToMB(nodes.Items[i].Status.Capacity.Memory().Value()),
			TotalEphemeral:       ToMB(nodes.Items[i].Status.Capacity.StorageEphemeral().Value()),

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Grant list/get on nodes.metrics.k8s.io via a ClusterRole + ClusterRoleBinding (e.g. the standard metrics-server scrapers view or kubectl create role/clusterrole with resource nodes.metrics.k8s.io)
  2. Verify with kubectl auth can-i list nodes.metrics.k8s.io
  3. If access is intentionally restricted, suppress the pulse/metrics views for this user instead of erroring

Example fix

// before
mx, err := metricsSrv.FetchNodesMetrics(ctx)

// after (defense: check first, degrade quietly)
auth, err := metricsSrv.CanI(client.ClusterScope, client.NmxGVR, "", client.ListAccess)
if err == nil && !auth {
    return nil, nil // no metrics permission; skip node metrics
}
mx, err := metricsSrv.FetchNodesMetrics(ctx)
Defensive patterns

Strategy: validation

Validate before calling

auth, err := metricsSrv.CanI(client.ClusterScope, client.NmxGVR, "", client.ListAccess)
if err == nil && !auth {
    return nil, nil // degrade: hide node metrics
}
mx, err := metricsSrv.FetchNodesMetrics(ctx)

Try / catch

if _, err := metricsSrv.FetchNodesMetrics(ctx); err != nil {
    if strings.Contains(err.Error(), "not authorized to list node metrics") {
        // hide pulse view / notify user about missing ClusterRole
    }
}

Prevention

When it happens

Trigger: Any call to FetchNodesMetrics or FetchNodeMetrics where CanI(ClusterScope, NmxGVR, "", [list]) returns false — i.e. no ClusterRole/Binding granting get/list on nodes.metrics.k8s.io.

Common situations: Restricted-view users provisioned only for core resources; operators on shared clusters where metrics are exposed only to SRE roles; fresh service-account used with k9s pulse view; cluster-role aggregation excluding metrics group.

Related errors


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