kubernetes/kops · error
failed to delete droplet: %d, err: %s
Error message
failed to delete droplet: %d, err: %s
What it means
deleteDroplet wraps the godo DropletsService.Delete failure during cluster teardown. It first converts the resource ID string to an int (separate error), then deletes; this error fires when DO refuses the droplet deletion — still-attached resources, permission, or the droplet already gone with a non-404 error.
Source
Thrown at pkg/resources/digitalocean/resources.go:263
resourceTracker.Blocks = blocks
resourceTrackers = append(resourceTrackers, resourceTracker)
}
}
return resourceTrackers, nil
}
func deleteDroplet(cloud fi.Cloud, t *resources.Resource) error {
c := cloud.(do.DOCloud)
dropletID, err := strconv.Atoi(t.ID)
if err != nil {
return fmt.Errorf("failed to convert droplet ID to int: %s", err)
}
_, err = c.DropletsService().Delete(context.TODO(), dropletID)
if err != nil {
return fmt.Errorf("failed to delete droplet: %d, err: %s", dropletID, err)
}
return nil
}
func deleteVPC(cloud fi.Cloud, t *resources.Resource) error {
c := cloud.(do.DOCloud)
_, err := c.VPCsService().Delete(context.TODO(), t.ID)
if err != nil {
return fmt.Errorf("failed to delete VPC %s (ID %s): %s", t.Name, t.ID, err)
}
return nil
}
func deleteVolume(cloud fi.Cloud, t *resources.Resource) error {
c := cloud.(do.DOCloud)
volume := t.Obj.(godo.Volume)View on GitHub (pinned to 4c8573c808)
Solutions
- Check the DigitalOcean API token and droplet delete permissions
- Retry after transient errors
- Verify the droplet ID is valid; 404 means it was already deleted
Example fix
// before # 403 insufficient scope // after export DIGITALOCEAN_ACCESS_TOKEN=<token with droplet:write scope> kops delete cluster --cloud digitalocean ...
Defensive patterns
Strategy: retry
Validate before calling
droplet, resp, err := c.DropletsService().Get(context.TODO(), dropletID)
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil // already deleted
} Try / catch
if _, err := c.DropletsService().Delete(context.TODO(), dropletID); err != nil {
var gerr *godo.ErrorResponse
if errors.As(err, &gerr) && gerr.Response.StatusCode == http.StatusNotFound {
return nil // idempotent: already gone
}
return fmt.Errorf("failed to delete droplet: %d, err: %w", dropletID, err)
} Prevention
- Make deletes idempotent by treating 404 as success
- Verify token write scope before teardown runs
- Avoid deleting droplets out-of-band while kops manages them
When it happens
Trigger: c.DropletsService().Delete(context.TODO(), dropletID) errors: droplet already gone (404), token lacking write scope (403), network/API failure.
Common situations: Droplet deleted out-of-band then kops delete re-run; expired token after cluster creation; DO API transient failure mid-teardown.
Related errors
- deleting droplets is not supported yet
- failed to apply resource record set: %s, err: %s
- failed to retrieve droplet %d: %w
- droplet %d not found
- droplet %d has unexpected status %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/73b1ce1744b5c9e9.
Report an issue: GitHub.