kubernetes/kops · warning

node not set

Error message

node not set

What it means

drainNode also requires the CloudInstance to carry its corresponding Kubernetes Node object. This guard error means the instance has no Node set, so there is nothing to drain. Callers normally pre-check u.Node == nil and skip drain, so this surfaces only from direct/edge calls.

Source

Thrown at pkg/instancegroups/instancegroups.go:676

	if err := c.Cloud.DeleteInstance(u); err != nil {
		if nodeName != "" {
			return fmt.Errorf("error deleting instance %q, node %q: %v", id, nodeName, err)
		}
		return fmt.Errorf("error deleting instance %q: %v", id, err)
	}

	return nil
}

// drainNode drains a K8s node.
func (c *RollingUpdateCluster) drainNode(ctx context.Context, u *cloudinstances.CloudInstance) error {
	if c.K8sClient == nil {
		return fmt.Errorf("K8sClient not set")
	}

	if u.Node == nil {
		return fmt.Errorf("node not set")
	}

	if u.Node.Name == "" {
		return fmt.Errorf("node name not set")
	}

	helper := &drain.Helper{
		Ctx:                 ctx,
		Client:              c.K8sClient,
		Force:               true,
		GracePeriodSeconds:  -1,
		IgnoreAllDaemonSets: true,
		Out:                 os.Stdout,
		ErrOut:              os.Stderr,
		Timeout:             c.DrainTimeout,

		// The zero value would retry evictions without any delay
		EvictErrorRetryDelay: 5 * time.Second,

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Skip draining when u.Node is nil (as drainTerminateAndWait does) and rely on cloud-level termination
  2. Wait for the instance's kubelet to register before rolling it
  3. Guard direct drainNode calls with a nil check on u.Node

Example fix

// before
c.drainNode(ctx, u)
// after
if u.Node != nil {
    c.drainNode(ctx, u)
}
Defensive patterns

Strategy: validation

Validate before calling

if u == nil || u.Node == nil {
    klog.Warningf("Skipping drain of instance %q, not registered in kubernetes", u.ID)
    return nil
}
c.drainNode(ctx, u)

Type guard

func hasNode(u *cloudinstances.CloudInstance) bool {
    return u != nil && u.Node != nil
}

Try / catch

if err := c.drainNode(ctx, u); err != nil {
    if err.Error() == "node not set" { return nil } // nothing registered to drain
    return err
}

Prevention

When it happens

Trigger: drainNode called with a CloudInstance whose Node field is nil — e.g. an instance not yet registered in the cluster or discovered before node registration, when the caller bypasses the drainTerminateAndWait nil-check.

Common situations: Freshly launched instances queried before kubelet registration; control-plane instances without node objects in some topologies; library consumers calling drainNode directly.

Related errors


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