kubernetes/kops · error

rollingUpdate is missing a k8s client

Error message

rollingUpdate is missing a k8s client

What it means

rollingUpdateInstanceGroup needs a Kubernetes client to cordon/drain nodes and await readiness. If RollingUpdateCluster.K8sClient is nil and CloudOnly mode is not enabled, the update cannot safely proceed and returns this error before touching instances.

Source

Thrown at pkg/instancegroups/instancegroups.go:127

	val = strings.TrimSpace(val)
	val = strings.ToLower(val)
	switch val {
	case "n":
		klog.Info("User signaled to stop")
		os.Exit(3)
	case "a":
		klog.Info("Always Yes, stop prompting for rest of hosts")
		stopPrompting = true
	}
	return stopPrompting, err
}

// RollingUpdate performs a rolling update on a list of instances.
func (c *RollingUpdateCluster) rollingUpdateInstanceGroup(ctx context.Context, group *cloudinstances.CloudInstanceGroup, sleepAfterTerminate time.Duration) (err error) {
	isBastion := group.InstanceGroup.IsBastion()
	// Do not need a k8s client if you are doing cloudonly.
	if c.K8sClient == nil && !c.CloudOnly {
		return fmt.Errorf("rollingUpdate is missing a k8s client")
	}

	noneReady := len(group.Ready) == 0
	numInstances := len(group.Ready) + len(group.NeedUpdate)
	update := group.NeedUpdate
	if c.Force {
		update = append(update, group.Ready...)
	}

	if len(update) == 0 {
		return nil
	}

	if isBastion {
		klog.V(3).Info("Not validating the cluster as instance is a bastion.")
	} else if err = c.maybeValidate("", 1, group); err != nil {
		return err
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Set K8sClient on RollingUpdateCluster to an initialized kubernetes.Clientset for the cluster
  2. Set CloudOnly=true if you intentionally want updates without Kubernetes API access
  3. Verify the cluster API is reachable so a client can be constructed

Example fix

// before
r := &RollingUpdateCluster{Cloud: cloud, Force: false}
// after
r := &RollingUpdateCluster{Cloud: cloud, K8sClient: clientset, Force: false}
Defensive patterns

Strategy: validation

Validate before calling

// Guard before constructing the rolling update
if r.K8sClient == nil && !r.CloudOnly {
	return fmt.Errorf("refusing to roll: K8sClient is nil and CloudOnly is false")
}

Type guard

func canRoll(r *RollingUpdateCluster) bool {
	return r.K8sClient != nil || r.CloudOnly
}

Try / catch

err := c.RollingUpdate(ctx, groups, &k8sClients)
if err != nil && strings.Contains(err.Error(), "missing a k8s client") {
	return fmt.Errorf("initialize K8sClient or set CloudOnly=true: %w", err)
}

Prevention

When it happens

Trigger: Constructing RollingUpdateCluster without setting K8sClient and without setting CloudOnly=true, then calling RollingUpdate on a non-bastion group.

Common situations: Tooling that only manipulates cloud state forgetting the client, building the struct literal in tests/tools and omitting K8sClient, or intending cloud-only mode but not setting the flag.

Related errors


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