{"record":{"id":"a23887f81cd34ef4","repo":"kubernetes/kops","slug":"error-deleting-volume-v","errorCode":null,"errorMessage":"error deleting volume: %v","messagePattern":"error deleting volume: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstack/volume.go","lineNumber":143,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn err\n\t} else if done {\n\t\treturn nil\n\t} else {\n\t\treturn wait.ErrWaitTimeout\n\t}\n}\n\nfunc (c *openstackCloud) DeleteVolume(volumeID string) error {\n\treturn deleteVolume(c, volumeID)\n}\n\nfunc deleteVolume(c OpenstackCloud, volumeID string) error {\n\tdone, err := vfs.RetryWithBackoff(deleteBackoff, func() (bool, error) {\n\t\terr := cinder.Delete(context.TODO(), c.BlockStorageClient(), volumeID, cinder.DeleteOpts{}).ExtractErr()\n\t\tif err != nil && !isNotFound(err) {\n\t\t\treturn false, fmt.Errorf(\"error deleting volume: %v\", err)\n\t\t}\n\t\tif isNotFound(err) {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t} else if done {\n\t\treturn nil\n\t} else {\n\t\treturn wait.ErrWaitTimeout\n\t}\n}\n","sourceCodeStart":125,"sourceCodeEnd":158,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstack/volume.go#L125-L158","documentation":"kops wraps any non-404 error from the Cinder block-storage volume delete call (upup/pkg/fi/cloudup/openstack/volume.go:143) inside deleteVolume, which retries with backoff via vfs.RetryWithBackoff. It means the OpenStack Block Storage API rejected or failed the DELETE /volumes/{id} request for a reason other than the volume already being gone. The underlying gophercloud error (auth, quota, state conflict, 5xx) is preserved in %v.","triggerScenarios":"Cinder returns 409 Conflict because the volume is attached to an instance or has snapshots/dependencies; 400 for a malformed volume ID; 401/403 from expired or insufficient Keystone credentials; transient 500/503 from the cinder service (retried until backoff steps exhausted).","commonSituations":"Tearing down a cluster while a volume is still attached to a node that has not fully terminated; deleting a cluster whose volumes have existing Cinder snapshots or backups; stale/revoked OpenStack credentials mid-teardown; Cinder service degraded or over capacity.","solutions":["Check the wrapped %v error for the HTTP status; if 409, detach the volume (or wait for the instance to terminate) and rerun `kops delete cluster` / the delete operation.","List snapshots/backups referencing the volume with `openstack volume snapshot list` and delete them before deleting the volume.","Verify credentials and project scope in the OpenStack cloud config (OS_* env or cloud.conf) and that the token has volume:v2 delete permissions.","If the volume is stuck, use `openstack volume set --state available <id>` (admin) or detach via Nova, then delete manually and rerun kops.","For persistent 5xx, check the Cinder service health / OpenStack provider status and retry later."],"exampleFix":"// before: deleting while volume still attached\ncloud.DeleteVolume(volumeID)\n// after: wait for detachment (or detach explicitly) before delete\nvolume, _ := cloud.GetVolume(volumeID)\nif len(volume.Attachments) > 0 {\n    return fmt.Errorf(\"volume %s still attached; retry after detach\", volumeID)\n}\nreturn cloud.DeleteVolume(volumeID)","handlingStrategy":"try-catch","validationCode":"// check volume state before delete\nv, err := cloud.GetVolume(volumeID)\nif err == nil && len(v.Attachments) > 0 {\n    return fmt.Errorf(\"volume %s attached to %v; detach first\", volumeID, v.Attachments)\n}","typeGuard":"func isNotFoundErr(err error) bool {\n    var gerr gophercloud.ErrUnexpectedResponseCode\n    return errors.As(err, &gerr) && gerr.Actual == http.StatusNotFound\n}","tryCatchPattern":"err := cloud.DeleteVolume(volumeID)\nif err != nil {\n    if strings.Contains(err.Error(), \"409\") || strings.Contains(err.Error(), \"Conflict\") {\n        // volume busy: detach/wait and retry\n    } else if isNotFoundErr(err) {\n        return nil // already gone\n    }\n    return err\n}","preventionTips":["Ensure nodes/volumes are detached before deleting a cluster","Delete Cinder snapshots and backups referencing the volume first","Rotate/validate OS_* credentials before long teardown runs","Check `openstack volume show` state is 'available' before manual deletes"],"tags":["openstack","cinder","volume","delete","retry"],"backgroundTag":"volume-delete-conflict","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}