derailed/k9s · error

%v access denied on resource %q:%q

Error message

%v access denied on resource %q:%q

What it means

Factory.CanForResource (internal/watch/factory.go:213) performs a SelfSubjectAccessReview (Client().CanI) for the given verbs on a resource in a namespace. When the server answers 'not allowed', k9s refuses to create an informer and returns this error listing the verbs, namespace and GVR. It is an RBAC denial surfaced before any watch/list attempt.

Source

Thrown at internal/watch/factory.go:213

	f.mx.RLock()
	defer f.mx.RUnlock()
	_, ok := f.factories[client.BlankNamespace]

	return ok
}

// CanForResource return an informer is user has access.
func (f *Factory) CanForResource(ns string, gvr *client.GVR, verbs []string) (informers.GenericInformer, error) {
	var resName string
	if gvr == client.NsGVR {
		resName = ns
	}
	auth, err := f.Client().CanI(ns, gvr, resName, verbs)
	if err != nil {
		return nil, err
	}
	if !auth {
		return nil, fmt.Errorf("%v access denied on resource %q:%q", verbs, ns, gvr)
	}

	// Namespaces are cluster-scoped; always use cluster scope for the informer
	if gvr == client.NsGVR {
		ns = client.ClusterScope
	}

	return f.ForResource(ns, gvr)
}

// CanForInstance return an informer is user has access.
func (f *Factory) CanForInstance(fqn string, gvr *client.GVR, verbs []string) (informers.GenericInformer, error) {
	ns, n := namespaced(fqn)
	if client.IsAllNamespace(ns) {
		ns = client.BlankNamespace
	}

	// For namespace resources, use the resource name as the namespace for RBAC

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Identify the missing verbs from the message and grant them via Role + RoleBinding in that namespace (see exampleFix)
  2. Verify current identity and permissions: 'kubectl auth whoami' and 'kubectl auth can-i --list -n <ns>'
  3. Run k9s with a kubeconfig that has broader rights, or point KUBECONFIG at the right context
  4. If denial is expected, avoid navigating to that resource view; k9s only calls CanForResource for features you invoke

Example fix

# before: [get list watch] access denied on resource "ns1":"apps/v1/deployments"
# after: grant RBAC
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: deploy-viewer
  namespace: ns1
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: deploy-viewer-binding
  namespace: ns1
subjects:
  - kind: User
    name: jane
roleRef:
  kind: Role
  name: deploy-viewer
  apiGroup: rbac.authorization.k8s.io
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check with the same SSAR call before building UI on the informer
if ok, err := f.Client().CanI(ns, gvr, "", []string{"get", "list", "watch"}); err == nil && !ok {
    // hide/disable the feature instead of erroring later
    return nil
}

Try / catch

// Go: treat the denial as a control-flow signal, not a crash
inf, err := f.CanForResource(ns, gvr, verbs)
if err != nil {
    if strings.Contains(err.Error(), "access denied") {
        slog.Warn("rbac denied", slog.String("gvr", gvr.String()), slog.String("ns", ns))
        return hideFeature(gvr)
    }
    return err
}

Prevention

When it happens

Trigger: Opening a view / running a feature that needs informers on a resource the current user has no get/list/watch (or the specific requested verbs) for in that namespace — e.g. ':events' with no list on events, xray on a cluster where the user is namespace-restricted.

Common situations: Restricted service-account kubeconfigs (CI, read-only auditor roles); missing RoleBinding for a new team member; typos in Role resourceNames; freshly created namespace without bindings; cluster-scope-only users browsing other namespaces.

Understand the failure class

Related errors


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