kubernetes/kops · error
error while waiting for volume %s to detach: %s
Error message
error while waiting for volume %s to detach: %s
What it means
Fires in deleteVolume when waitForDetach fails after DetachByDropletID was accepted — the volume detach action did not complete in time or errored while waiting, so deletion is aborted to avoid destroying an attached volume.
Source
Thrown at pkg/resources/digitalocean/resources.go:293
return nil
}
func deleteVolume(cloud fi.Cloud, t *resources.Resource) error {
c := cloud.(do.DOCloud)
volume := t.Obj.(godo.Volume)
for _, dropletID := range volume.DropletIDs {
action, resp, err := c.VolumeActionService().DetachByDropletID(context.TODO(), volume.ID, dropletID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
// Volume is already detached, nothing to do.
continue
}
return fmt.Errorf("failed to detach volume %s: %s", volume.ID, err)
}
if err := waitForDetach(c, action); err != nil {
return fmt.Errorf("error while waiting for volume %s to detach: %s", volume.ID, err)
}
}
_, err := c.VolumeService().DeleteVolume(context.TODO(), t.ID)
if err != nil {
return fmt.Errorf("failed to delete volume: %s, err: %s", t.ID, err)
}
return nil
}
func deleteRecord(cloud fi.Cloud, domain string, t *resources.Resource) error {
c := cloud.(do.DOCloud)
record := t.Obj.(godo.DomainRecord)
_, err := c.DomainService().DeleteRecord(context.TODO(), domain, record.ID)
if err != nil {
return fmt.Errorf("failed to delete record for domain %s: %d", domain, record.ID)View on GitHub (pinned to 4c8573c808)
Solutions
- Wait for the detach action to complete in DigitalOcean and retry deletion
- Check the volume's droplet attachments via the DO console
- If the detach action failed, inspect the action's error in the DO API
Example fix
// before # action stuck "in-progress" until timeout // after # stop the droplet or force-detach manually doctl compute droplet-action power-off <droplet-id> kops delete cluster --cloud digitalocean ...
Defensive patterns
Strategy: retry
Validate before calling
deadline := time.Now().Add(5 * time.Minute)
for time.Now().Before(deadline) {
a, _, err := c.ActionsService().Get(context.TODO(), action.ID)
if err != nil { return err }
if a.Status == godo.ActionCompleted { return nil }
time.Sleep(10 * time.Second)
}
return errors.New("timed out waiting for volume detach") Try / catch
if err := waitForDetach(c, action); err != nil {
// one re-poll before failing
time.Sleep(30 * time.Second)
if err2 := waitForDetach(c, action); err2 != nil {
return fmt.Errorf("error while waiting for volume %s to detach: %w", volume.ID, err2)
}
} Prevention
- Use generous polling timeouts for volume detach on busy volumes
- Back off poll intervals to avoid rate limits
- Power off the droplet before detaching if detach repeatedly stalls
When it happens
Trigger: waitForDetach polls the action status and returns error on action failure, polling API error, or timeout while the detach stays in-progress.
Common situations: DO action stuck/failing due to heavy I/O on the volume; polling hit rate limits; temporary API outage during the wait loop.
Related errors
- failed to detach volume %s: %s
- failed to delete volume: %s, err: %s
- fail to stop DO instance %v in 5 mins
- DIGITALOCEAN_ACCESS_TOKEN is required
- DIGITALOCEAN_ACCESS_TOKEN is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/f19de4fbf0b84b0b.
Report an issue: GitHub.