kubernetes/kops · error

failed to delete volume %s(%s): %w

Error message

failed to delete volume %s(%s): %w

What it means

Wrapped error from deleteVolume: hcloud VolumeClient.Delete failed while kOps removes a cluster volume. Commonly the underlying error is hcloud's 'volume is still attached' conflict, since volumes must be detached (or their server deleted) first.

Source

Thrown at pkg/resources/hetzner/resources.go:310

	}

	_, errCh := actionClient.WatchProgress(ctx, result.Action)
	if err := <-errCh; err != nil {
		return err
	}

	return nil
}

func deleteVolume(cloud fi.Cloud, r *resources.Resource) error {
	klog.Infof("Deleting Volume: %s(%s)", r.Name, r.ID)

	c := cloud.(hetzner.HetznerCloud)
	client := c.VolumeClient()
	volume := r.Obj.(*hcloud.Volume)
	_, err := client.Delete(context.TODO(), volume)
	if err != nil {
		return fmt.Errorf("failed to delete volume %s(%s): %w", r.Name, r.ID, err)
	}

	return nil
}

func dumpServer(op *resources.DumpOperation, r *resources.Resource) error {
	server := r.Obj.(*hcloud.Server)

	data := make(map[string]interface{})
	data["id"] = r.ID
	data["type"] = r.Type
	data["raw"] = r.Obj
	op.Dump.Resources = append(op.Dump.Resources, data)

	i := &resources.Instance{
		Name: r.ID,
	}
	if ip := server.PublicNet.IPv4.IP; ip != nil {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Detach the volume from its server (console: `hcloud volume detach`) or delete the attached server, then retry.
  2. Verify HCLOUD_TOKEN validity and write scope.
  3. If not-found, the volume is already gone — rerun delete.
  4. Retry after any rate-limit window indicated by the wrapped error.

Example fix

// before: attached volume blocks delete
client.Delete(context.TODO(), volume) // volume is still attached to server X
// after: detach first
_, _, _ = actionClient.AttachVolume(ctx, server, hcloud.VolumeAttachOpts{Volume: volume}) // opposite op used at create
// at teardown ensure servers are deleted before volumes (kOps ordering already does this);
// for manual cleanup: hcloud volume detach <id> && kops delete cluster ...
Defensive patterns

Strategy: try-catch

Validate before calling

vol, _, err := c.Volume.Get(ctx, strconv.Itoa(volumeID))
if err != nil { return err }
if vol == nil { return nil }
if vol.Server != nil {
    return fmt.Errorf("volume %d still attached to server %d", volumeID, vol.Server.ID)
}

Type guard

func isAttachedVolumeError(err error) bool {
    var hErr hcloud.Error
    return errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeVolumeAttached
}

Try / catch

err := deleteVolume(...)
var hErr hcloud.Error
switch {
case err == nil:
    return nil
case errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeNotFound:
    return nil
case errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeVolumeAttached:
    return detachVolumeThenRetry(err)
default:
    return err
}

Prevention

When it happens

Trigger: client.Delete(ctx, volume) fails: volume attached to a server (hcloud conflict), invalid token, rate limit, or volume already deleted.

Common situations: Server crashed or was deleted out-of-band leaving attached volumes; PVC-backed volumes whose server teardown ordering raced; credential rotation mid-delete.

Related errors


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