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
- Check whether the droplet still exists (doctl compute droplet get <id>); if deleted externally, refresh state with `kops update cluster` and re-run
- Verify API token validity and scopes for the duration of the operation
- Retry the rolling update after transient DO API issues resolve
- 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
- Treat 404 during the wait loop as success (droplet already gone)
- Keep API tokens valid for the full 5-minute wait window
- Avoid manual console deletion during rolling updates
- Add retry/backoff around poll failures for transient API errors
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
- error stopping instance %d: %v
- failed to apply resource record set: %s, err: %s
- failed to list lbs: %v
- failed to delete droplet: %d, err: %s
- failed to delete VPC %s (ID %s): %s
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/78d0b0aa1e3d9eb1.
Report an issue: GitHub.