derailed/k9s · error

user is not authorized to list pods metrics

Error message

user is not authorized to list pods metrics

What it means

Raised at internal/client/metrics.go:100 inside checkAccess when the RBAC check for pods.metrics.k8s.io in a namespace returns auth=false. The message string is the const in FetchPodsMetrics (metrics.go:232); the check runs at metrics.go:237 against PmxGVR in the (possibly BlankNamespace for all-namespaces) scope. It indicates the connection is healthy and metrics-server exists, but the user cannot list pod metrics in that namespace.

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. Add a Role/ClusterRole granting get/list on pods.metrics.k8s.io and bind it in the target namespace(s) (kubectl auth can-i list pods.metrics.k8s.io -n ns to verify)
  2. For all-namespaces browsing, use a ClusterRoleBinding instead of per-namespace RoleBindings
  3. If denial is intended, disable/skip metrics columns and pulse for that user

Example fix

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

// after
auth, err := metricsSrv.CanI(ns, client.PmxGVR, "", client.ListAccess)
if err == nil && !auth {
    return nil, nil // degrade: no pod-metrics permission in ns
}
mx, err := metricsSrv.FetchPodsMetrics(ctx, ns)
Defensive patterns

Strategy: validation

Validate before calling

auth, err := metricsSrv.CanI(ns, client.PmxGVR, "", client.ListAccess)
if err == nil && !auth {
    return nil, nil // skip metrics for this namespace
}
mx, err := metricsSrv.FetchPodsMetrics(ctx, ns)

Try / catch

if _, err := metricsSrv.FetchPodsMetrics(ctx, ns); err != nil {
    if strings.Contains(err.Error(), "not authorized to list pods metrics") {
        // blank the metrics columns for ns; suggest RoleBinding fix
    }
}

Prevention

When it happens

Trigger: Calling FetchPodsMetrics(ctx, ns) (directly or via FetchPodsMetricsMap) when CanI(ns, PmxGVR, "", [list]) is false; also hit when browsing pods in 'all namespaces' mode where ns becomes BlankNamespace and a cluster-wide grant is required.

Common situations: Namespace-scoped users whose RoleBindings cover deployments/pods but not the metrics.k8s.io group; all-namespace view without a ClusterRole for pods.metrics.k8s.io; k9s pulse view opened by an on-call account with minimal grants.

Related errors


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