derailed/k9s · error

user is not authorized to scale: %s

Error message

user is not authorized to scale: %s

What it means

scaleRes (internal/dao/dp.go:362-374) scales Deployments and StatefulSets. It authorizes against the scale SUBRESOURCE - client.NewGVR(gvr.String()+":scale") - requiring get AND update on e.g. deployments/scale in the namespace. Denial returns this error printing the GVR (e.g. apps/v1:deployments).

Source

Thrown at internal/dao/dp.go:368

		if e.ValueFrom == nil || e.ValueFrom.ConfigMapKeyRef == nil {
			continue
		}
		if e.ValueFrom.ConfigMapKeyRef.Name == name {
			return true
		}
	}

	return false
}

func scaleRes(ctx context.Context, f Factory, gvr *client.GVR, path string, replicas int32) error {
	ns, n := client.Namespaced(path)
	auth, err := f.Client().CanI(ns, client.NewGVR(gvr.String()+":scale"), n, []string{client.GetVerb, client.UpdateVerb})
	if err != nil {
		return err
	}
	if !auth {
		return fmt.Errorf("user is not authorized to scale: %s", gvr)
	}

	dial, err := f.Client().Dial()
	if err != nil {
		return err
	}

	switch gvr {
	case client.DpGVR:
		scale, e := dial.AppsV1().Deployments(ns).GetScale(ctx, n, metav1.GetOptions{})
		if e != nil {
			return e
		}
		scale.Spec.Replicas = replicas
		_, e = dial.AppsV1().Deployments(ns).UpdateScale(ctx, n, scale, metav1.UpdateOptions{})
		return e
	case client.StsGVR:
		scale, e := dial.AppsV1().StatefulSets(ns).GetScale(ctx, n, metav1.GetOptions{})

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Verify exactly this check: kubectl auth can-i update deployments/scale -n <ns>
  2. Extend the Role with resources: ["deployments/scale","statefulsets/scale"] (or "*/scale"), verbs: ["get","update"]
  3. Also keep get/update on the parent resource, which many clients still use
  4. If scale RBAC is intentionally locked, request scaling through the platform's approved channel
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight the exact subresource check scaleRes performs.
func CanScale(c client.Client, gvr *client.GVR, ns string) (bool, error) {
	return c.CanI(ns, client.NewGVR(gvr.String()+":scale"), "", []string{client.GetVerb, client.UpdateVerb})
}

Try / catch

if err := scaleRes(ctx, f, gvr, path, n); err != nil {
    if strings.Contains(err.Error(), "not authorized to scale") {
        return fmt.Errorf("RBAC: grant get+update on %s/scale in %s", gvr, ns)
    }
    return err
}

Prevention

When it happens

Trigger: Scaling a Deployment/StatefulSet while the identity lacks get/update on the `<resource>/scale` subresource in RBAC (resources: ["deployments/scale"] or ["statefulsets/scale"]). Note: having get/update on deployments itself does not automatically cover the scale subresource in RBAC - subresources are authorized separately.

Common situations: Least-privilege roles that scale via the main resource but forget the /scale subresource entry; clusters where platform teams grant patch-only scaling; impersonated service accounts in automation.

Related errors


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