{"record":{"id":"286282ef9e32f706","repo":"derailed/k9s","slug":"user-is-not-authorized-to-list-pods","errorCode":null,"errorMessage":"user is not authorized to list pods","messagePattern":"user is not authorized to list pods","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/recorder.go","lineNumber":282,"sourceCode":"\t\tr.series.Add(pt.Time, pt, seriesCacheExpiry)\n\t\tr.mx.Lock()\n\t\tdefer r.mx.Unlock()\n\t\tif r.mxChan != nil {\n\t\t\tr.mxChan <- TimeSeries{pt}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// FetchPods retrieves all pods in a given namespace.\nfunc FetchPods(_ context.Context, f Factory, ns string) (*v1.PodList, error) {\n\tauth, err := f.Client().CanI(ns, client.PodGVR, \"pods\", []string{client.ListVerb})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !auth {\n\t\treturn nil, fmt.Errorf(\"user is not authorized to list pods\")\n\t}\n\n\too, err := f.List(client.PodGVR, ns, false, labels.Everything())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpp := make([]v1.Pod, 0, len(oo))\n\tfor _, o := range oo {\n\t\tvar pod v1.Pod\n\t\terr = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpp = append(pp, pod)\n\t}\n\n\treturn &v1.PodList{Items: pp}, nil\n}","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/recorder.go#L264-L300","documentation":"FetchPods (used by the recorder/alarm fan-out) authorizes list on pods in namespace ns via CanI and errors when denied. The requirement is the list verb on core pods in that specific namespace — nothing namespace-scoped shorter than that will pass.","triggerScenarios":"CanI(ns, pods, list) false — the active identity has no Role/RoleBinding granting pod list in the namespace being scanned.","commonSituations":"Recorder or cross-namespace features walking into namespaces the user cannot read; service accounts scoped to one namespace used against another; kubeconfig contexts switched after the session started.","solutions":["Grant list on pods in the namespace: resources [\"pods\"] verbs [\"list\",\"get\"] via Role+RoleBinding","Verify: kubectl auth can-i list pods -n <ns>","Restrict the feature to namespaces the identity can read instead of granting cluster-wide access"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"ok, err := f.Client().CanI(ns, client.PodGVR, \"\", []string{\"list\"})\nif err != nil { return err }\nif !ok { return fmt.Errorf(\"cannot list pods in %s; skipping\", ns) }","typeGuard":null,"tryCatchPattern":"if _, err := dao.FetchPods(ctx, f, ns); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to list pods\") {\n        // skip this namespace in fan-out loops instead of aborting the run\n    }\n}","preventionTips":["Scope recorder/fan-out features to namespaces the identity can list","Precompute authorized namespaces once instead of failing per namespace","Grant list+get on pods together — consumers usually need both"],"tags":["kubernetes","rbac","pod","list","recorder"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}