kubernetes/kops · error

error describing instance %d: %v

Error message

error describing instance %d: %v

What it means

While waiting up to 5 minutes for the droplet to reach status 'off', DeleteInstance polls c.Client.Droplets.Get every minute. If a poll fails, kOps wraps the error as 'error describing instance <id>'. The deletion flow cannot confirm shutdown progress, so it fails.

Source

Thrown at upup/pkg/fi/cloudup/do/cloud.go:148

	return nil
}

func (c *doCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstance) error {
	dropletID, err := strconv.Atoi(i.ID)
	if err != nil {
		return fmt.Errorf("failed to convert droplet ID to int: %s", err)
	}

	_, _, err = c.Client.DropletActions.Shutdown(context.TODO(), dropletID)
	if err != nil {
		return fmt.Errorf("error stopping instance %d: %v", dropletID, err)
	}

	// Wait for 5 min to stop the instance
	for i := 0; i < 5; i++ {
		droplet, _, err := c.Client.Droplets.Get(context.TODO(), dropletID)
		if err != nil {
			return fmt.Errorf("error describing instance %d: %v", dropletID, err)
		}

		klog.V(8).Infof("stopping DO instance %q, current Status: %q", droplet, droplet.Status)

		if droplet.Status == "off" {
			break
		}

		if i == 5 {
			return fmt.Errorf("fail to stop DO instance %v in 5 mins", dropletID)
		}

		time.Sleep(time.Minute * 1)
	}

	_, err = c.Client.Droplets.Delete(context.TODO(), dropletID)
	if err != nil {
		return fmt.Errorf("error stopping instance %d: %v", dropletID, err)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check whether the droplet still exists (doctl compute droplet get <id>); if deleted externally, refresh state with `kops update cluster` and re-run
  2. Verify API token validity and scopes for the duration of the operation
  3. Retry the rolling update after transient DO API issues resolve
  4. Avoid manual droplet deletion during kOps rolling operations; use kops as the single writer

Example fix

// before
# droplet deleted manually mid rolling-update -> Get() 404
// after
kops update cluster --name cluster.example.com --yes   # resync cloud state
kops rolling-update cluster --name cluster.example.com --yes
Defensive patterns

Strategy: try-catch

Validate before calling

_, _, err := client.Droplets.Get(ctx, dropletID)
if err != nil {
    return fmt.Errorf("droplet %d not describable; aborting shutdown wait", dropletID)
}

Try / catch

droplet, _, err := c.Client.Droplets.Get(ctx, dropletID)
if err != nil {
    if gErr, ok := err.(godo.ErrorResponse); ok && gErr.Response.StatusCode == 404 {
        break // deleted externally; proceed
    }
    return fmt.Errorf("error describing instance %d: %v", dropletID, err)
}

Prevention

When it happens

Trigger: Droplets.Get returns an error during the 5-minute shutdown wait loop: droplet was deleted out-of-band mid-poll (DO returns 404), DO API auth/token failure, transient DO API outage or rate limiting between polls.

Common situations: User deleted the droplet manually while a rolling update was in flight; API token revoked mid-operation; DO status page incident; heavy rate limiting from many concurrent deletes.

Related errors


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