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
- Set K8sClient on RollingUpdateCluster to an initialized kubernetes.Clientset for the cluster
- Set CloudOnly=true if you intentionally want updates without Kubernetes API access
- 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
- Always set K8sClient when constructing RollingUpdateCluster unless intentionally cloud-only
- Add an explicit constructor/validation function for RollingUpdateCluster
- Document CloudOnly implications so it is not set as a workaround for a nil client
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
- unknown group type for group %q
- errShutdown
- timed out waiting for volume to detach
- DeviceName not set for volume
- DeleteGroup not implemented on azureCloud
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/d8bde4c283959162.
Report an issue: GitHub.