hashicorp/nomad · error
snapshot %q could not be deleted because it is in use: %v
Error message
snapshot %q could not be deleted because it is in use: %v
What it means
ControllerDeleteSnapshot translates gRPC codes.FailedPrecondition from the plugin's DeleteSnapshot RPC per the CSI spec: the snapshot exists but cannot be deleted because something depends on it (e.g. a volume created/restored from it, or an in-progress clone). Nomad surfaces this as 'in use' so the operator knows the delete is blocked by a dependency, not a transient fault.
Source
Thrown at plugins/csi/client.go:694
if err := c.ensureConnected(ctx); err != nil {
return err
}
err := req.Validate()
if err != nil {
return err
}
creq := req.ToCSIRepresentation()
_, err = c.controllerClient.DeleteSnapshot(ctx, creq, opts...)
// these standard gRPC error codes are overloaded with CSI-specific
// meanings, so translate them into user-understandable terms
// https://github.com/container-storage-interface/spec/blob/master/spec.md#deletesnapshot-errors
if err != nil {
code := status.Code(err)
switch code {
case codes.FailedPrecondition:
return fmt.Errorf(
"snapshot %q could not be deleted because it is in use: %v",
req.SnapshotID, err)
case codes.Aborted:
return fmt.Errorf("snapshot %q has a pending operation: %v", req.SnapshotID, err)
case codes.Internal:
return fmt.Errorf(
"controller plugin returned an internal error, check the plugin allocation logs for more information: %v", err)
}
return err
}
return nil
}
func (c *client) ControllerListSnapshots(ctx context.Context, req *ControllerListSnapshotsRequest, opts ...grpc.CallOption) (*ControllerListSnapshotsResponse, error) {
if err := c.ensureConnected(ctx); err != nil {
return nil, err
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Find and delete (or finish) the dependent volumes/restores created from this snapshot before retrying.
- Reorder the cleanup workflow: delete dependent volumes first, then the snapshot.
- Exclude in-use snapshots from the retention/pruning list (check snapshot dependencies via backend tooling).
- Confirm req.SnapshotID is correct — a stale/wrong ID may point at a snapshot that is genuinely in use.
Example fix
// before: blind prune
for _, s := range snapshots { deleteSnapshot(s.ID) }
// after: skip snapshots with dependents
for _, s := range snapshots {
if !hasDependentVolumes(s.ID) { deleteSnapshot(s.ID) }
} Defensive patterns
Strategy: validation
Validate before calling
func canDeleteSnapshot(ctx context.Context, c *client, snapID string) error {
vols, err := listVolumesSourcedFromSnapshot(ctx, c, snapID) // backend/driver API
if err != nil { return err }
if len(vols) > 0 {
return fmt.Errorf("snapshot %s in use by %d volumes", snapID, len(vols))
}
return nil
} Try / catch
err := c.ControllerDeleteSnapshot(ctx, req)
if err != nil && strings.Contains(err.Error(), "in use") {
log.Printf("deferring delete of %s: dependent resources exist", req.SnapshotID)
return ErrSnapshotInUse // handle in a later cleanup pass
} Prevention
- Delete dependent volumes/clones before pruning their source snapshots.
- Tag snapshots with dependency metadata your cleanup job can check.
- Keep restores and retention windows non-overlapping.
When it happens
Trigger: Calling ControllerDeleteSnapshot with req.SnapshotID for a snapshot that is the source of an existing volume, an active restore, or a dependent clone, and the plugin returns codes.FailedPrecondition (client.go:694).
Common situations: Trying to prune snapshots still referenced by running CSI volumes; a restore job is consuming the snapshot; retention policy deleting snapshots linked to downstream copies on the array; cloud provider blocks deleting a snapshot used by another disk.
Related errors
- snapshot %q already exists but is incompatible with volume I
- requested mount flags did not match available capabilities
- snapshot %q is already pending: %v
- storage provider does not have enough space for this snapsho
- snapshot %q has a pending operation: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/2bf6cde955eb20b0.
Report an issue: GitHub.