kubernetes/kops · error

InstanceGroups::Delete not supported for server-side client

Error message

InstanceGroups::Delete not supported for server-side client

What it means

Delete on the server-side instanceGroups client is a deliberate stub: removing instance groups is a provisioning operation owned by kops CLI tooling, not the controller, so it always fails with this error.

Source

Thrown at cmd/kops-controller/pkg/controllerclientset/instancegroups.go:108

		return nil, err
	}
	list.Items = items.([]kopsapi.InstanceGroup)
	for i := range list.Items {
		c.addLabels(&list.Items[i])
	}
	return list, nil
}

func (c *instanceGroups) Create(ctx context.Context, g *kopsapi.InstanceGroup, opts metav1.CreateOptions) (*kopsapi.InstanceGroup, error) {
	return nil, fmt.Errorf("InstanceGroups::Create not supported for server-side client")
}

func (c *instanceGroups) Update(ctx context.Context, g *kopsapi.InstanceGroup, opts metav1.UpdateOptions) (*kopsapi.InstanceGroup, error) {
	return nil, fmt.Errorf("InstanceGroups::Update not supported for server-side client")
}

func (c *instanceGroups) Delete(ctx context.Context, name string, options metav1.DeleteOptions) error {
	return fmt.Errorf("InstanceGroups::Delete not supported for server-side client")
}

func (r *instanceGroups) DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	return fmt.Errorf("InstanceGroups::DeleteCollection not supported for server-side client")
}

func (r *instanceGroups) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
	return nil, fmt.Errorf("InstanceGroups::Watch not supported for server-side client")
}

func (r *instanceGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *kopsapi.InstanceGroup, err error) {
	return nil, fmt.Errorf("InstanceGroups::Patch not supported for server-side client")
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Delete instance groups via the CLI: kops delete ig <name> --yes, then kops update cluster --yes and rolling-update
  2. Trigger deletion externally (CI, operator invoking kops) instead of in-process
  3. Keep the controller read-only with respect to instance group lifecycle

Example fix

// before
err := igs.Delete(ctx, "nodepool-a", metav1.DeleteOptions{})
// after
// $ kops delete ig nodepool-a --name mycluster.example.com --yes
err := nil // controller only reads: igs.Get(ctx, "nodepool-a", metav1.GetOptions{})
Defensive patterns

Strategy: validation

Validate before calling

if isReadOnlyInstanceGroupClient(igs) {
  return errors.New("instance group deletion must be done via `kops delete ig` CLI")
}

Try / catch

err := igs.Delete(ctx, name, metav1.DeleteOptions{})
if err != nil && strings.Contains(err.Error(), "Delete not supported") {
  // delegate: kops delete ig <name> --yes
  return deleteInstanceGroupViaCLI(ctx, name)
}

Prevention

When it happens

Trigger: Calling instanceGroups.Delete(ctx, name, metav1.DeleteOptions{}) on the controller's interface, e.g. an auto-removal of empty node pools inside kops-controller.

Common situations: Porting `kops delete ig` logic into an operator; writing garbage-collection routines that prune unused instance groups at runtime.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/a882040c55acc01e. Report an issue: GitHub.