derailed/k9s · error
unsupported resource for scaling
Error message
unsupported resource for scaling: %s
What it means
scaleRes (internal/dao/dp.go:394-396) supports exactly two GVRs - client.DpGVR (Deployments) and client.StsGVR (StatefulSets). Any other GVR that reaches this generic helper falls through the switch's default and is rejected with this message printing the GVR.
Solutions
- Scale only Deployments or StatefulSets through this path
- For other scalable kinds, use the resource-specific client (e.g. dial.AppsV1().ReplicaSets(ns).UpdateScale) or kubectl scale
- If you control the code, add a case for the GVR before the default branch
Example fix
// before
scaleRes(ctx, f, client.RsGVR, path, 3) // falls into default
// after
case client.RsGVR:
scale, e := dial.AppsV1().ReplicaSets(ns).GetScale(ctx, n, metav1.GetOptions{})
if e != nil { return e }
scale.Spec.Replicas = replicas
_, e = dial.AppsV1().ReplicaSets(ns).UpdateScale(ctx, n, scale, metav1.UpdateOptions{})
return e Defensive patterns
Strategy: type-guard
Validate before calling
// Reject unsupported GVRs before any authorization or API traffic.
func Scalable(gvr *client.GVR) bool {
return gvr == client.DpGVR || gvr == client.StsGVR
} Type guard
func ScaleTarget(gvr *client.GVR) (apply func(ctx context.Context, ns, name string, replicas int32) error, err error) {
switch gvr {
case client.DpGVR:
return applyDpScale, nil
case client.StsGVR:
return applyStsScale, nil
default:
return nil, fmt.Errorf("unsupported resource for scaling: %s", gvr)
}
} Try / catch
if !Scalable(gvr) { return fmt.Errorf("unsupported resource for scaling: %s", gvr) }
return scaleRes(ctx, f, gvr, path, replicas) Prevention
- Type-guard at the call site: never route ReplicaSets/CRDs into the shared scale helper
- When adding a scalable kind, extend the switch AND the RBAC pre-check list together
When it happens
Trigger: Routing a scale request for an unsupported kind through scaleRes - e.g. a Replicaset, ReplicationController, or a custom CRD with a scale subresource. Authorization (error 113) is checked before this switch, so you only see this error after RBAC passed.
Common situations: Extending k9s DAOs or writing plugins that call the scale path for other controllers; version drift where a caller assumed a GVR was added to the supported set.
Related errors
- user is not authorized to scale
- expected ReferenceRes, but got %T
- expected SubjectRes, but got %T
- expected Unstructured, but got %T
- expected Unstructured, but got %T
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/df79182a01dcc730.
Report an issue: GitHub.
Appendix: source
Thrown at internal/dao/dp.go:394
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{})
if e != nil {
return e
}
scale.Spec.Replicas = replicas
_, e = dial.AppsV1().StatefulSets(ns).UpdateScale(ctx, n, scale, metav1.UpdateOptions{})
return e
default:
return fmt.Errorf("unsupported resource for scaling: %s", gvr)
}
}
func restartRes[T runtime.Object](ctx context.Context, f Factory, gvr *client.GVR, path string, opts *metav1.PatchOptions) error {
o, err := f.Get(gvr, path, true, labels.Everything())
if err != nil {
return err
}
var r = new(T)
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, r)
if err != nil {
return err
}
ns, n := client.Namespaced(path)
auth, err := f.Client().CanI(ns, gvr, n, client.PatchAccess)
if err != nil {
return errView on GitHub (pinned to 2d3ccc6ba2)