{"record":{"id":"3ae7098648e22b95","repo":"derailed/k9s","slug":"user-is-not-authorized-to-list-pods-metrics","errorCode":null,"errorMessage":"user is not authorized to list pods metrics","messagePattern":"user is not authorized to list pods metrics","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/metrics.go","lineNumber":100,"sourceCode":"\t\ttcpu += mx.AllocatableCPU\n\t\ttmem += mx.AllocatableMEM\n\t}\n\tmx.PercCPU, mx.PercMEM = ToPercentage(ccpu, tcpu), ToPercentage(cmem, tmem)\n\n\treturn nil\n}\n\nfunc (m *MetricsServer) checkAccess(ns string, gvr *GVR, msg string) error {\n\tif !m.HasMetrics() {\n\t\treturn errors.New(\"no metrics-server detected on cluster\")\n\t}\n\n\tauth, err := m.CanI(ns, gvr, \"\", ListAccess)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !auth {\n\t\treturn errors.New(msg)\n\t}\n\treturn nil\n}\n\n// NodesMetrics retrieves metrics for a given set of nodes.\nfunc (*MetricsServer) NodesMetrics(nodes *v1.NodeList, metrics *mv1beta1.NodeMetricsList, mmx NodesMetrics) {\n\tif nodes == nil || metrics == nil {\n\t\treturn\n\t}\n\n\tfor i := range nodes.Items {\n\t\tmmx[nodes.Items[i].Name] = NodeMetrics{\n\t\t\tAllocatableCPU:       nodes.Items[i].Status.Allocatable.Cpu().MilliValue(),\n\t\t\tAllocatableMEM:       ToMB(nodes.Items[i].Status.Allocatable.Memory().Value()),\n\t\t\tAllocatableEphemeral: ToMB(nodes.Items[i].Status.Allocatable.StorageEphemeral().Value()),\n\t\t\tTotalCPU:             nodes.Items[i].Status.Capacity.Cpu().MilliValue(),\n\t\t\tTotalMEM:             ToMB(nodes.Items[i].Status.Capacity.Memory().Value()),\n\t\t\tTotalEphemeral:       ToMB(nodes.Items[i].Status.Capacity.StorageEphemeral().Value()),","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/client/metrics.go#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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)","For all-namespaces browsing, use a ClusterRoleBinding instead of per-namespace RoleBindings","If denial is intended, disable/skip metrics columns and pulse for that user"],"exampleFix":"// before\nmx, err := metricsSrv.FetchPodsMetrics(ctx, ns)\n\n// after\nauth, err := metricsSrv.CanI(ns, client.PmxGVR, \"\", client.ListAccess)\nif err == nil && !auth {\n    return nil, nil // degrade: no pod-metrics permission in ns\n}\nmx, err := metricsSrv.FetchPodsMetrics(ctx, ns)","handlingStrategy":"validation","validationCode":"auth, err := metricsSrv.CanI(ns, client.PmxGVR, \"\", client.ListAccess)\nif err == nil && !auth {\n    return nil, nil // skip metrics for this namespace\n}\nmx, err := metricsSrv.FetchPodsMetrics(ctx, ns)","typeGuard":null,"tryCatchPattern":"if _, err := metricsSrv.FetchPodsMetrics(ctx, ns); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to list pods metrics\") {\n        // blank the metrics columns for ns; suggest RoleBinding fix\n    }\n}","preventionTips":["Cache per-namespace CanI results for the session to avoid repeated reviews","Add pods.metrics.k8s.io to namespaced Roles you hand to teams","For all-namespace views, require the cluster-scoped grant up front"],"tags":["kubernetes","rbac","metrics-server","namespace","authorization"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}