kubernetes/kops · error

error stopping instance %d: %v

Error message

error stopping instance %d: %v

What it means

After parsing the droplet ID, DeleteInstance calls the DO DropletActions.Shutdown API to gracefully power off the droplet. If that API call fails, the error is wrapped as 'error stopping instance <id>'. The instance is not deleted and the rolling-delete flow aborts.

Source

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

	klog.V(8).Info("digitalocean cloud provider DeleteGroup not implemented yet")
	return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time")
}

// DeregisterInstance drains a cloud instance and loadbalancers.
func (c *doCloudImplementation) DeregisterInstance(i *cloudinstances.CloudInstance) error {
	klog.V(8).Info("DO DeregisterInstance not implemented")
	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)
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the DO API token is valid and has write scope (doctl auth check / doctl compute droplet get <id>)
  2. Confirm the droplet still exists; if deleted manually, refresh kOps cloud state via `kops update cluster`
  3. Retry the rolling update — DO transient errors usually clear
  4. If the droplet is stuck, power it off via doctl then let kOps proceed

Example fix

// before
export DIGITALOCEAN_ACCESS_TOKEN=expired_token
// after
export DIGITALOCEAN_ACCESS_TOKEN=<valid token with write scope>
kops rolling-update cluster --name cluster.example.com --yes
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: token works and droplet exists
_, _, err := client.Droplets.Get(ctx, dropletID)
if err != nil {
    return fmt.Errorf("droplet %d unreachable before shutdown: %w", dropletID, err)
}

Try / catch

_, _, err := c.Client.DropletActions.Shutdown(ctx, dropletID)
if err != nil {
    if gErr, ok := err.(godo.ErrorResponse); ok && gErr.Response.StatusCode == 404 {
        return nil // already gone; treat as success
    }
    return fmt.Errorf("error stopping instance %d: %v", dropletID, err)
}

Prevention

When it happens

Trigger: DropletActions.Shutdown returns an error during `kops delete instance`/rolling update on DO: droplet already powered off/deleted, DO API auth failure (invalid token), droplet ID no longer exists, or DO API 5xx/rate-limit response.

Common situations: Expired or revoked DigitalOcean API token; droplet deleted manually in the DO console while kOps tries to delete it; transient DO API outage.

Related errors


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