hashicorp/nomad · warning

volume in use: %s

Error message

volume in use: %s

What it means

CSIVolumeDeregister refuses to remove a volume whose InUse() reports active claims (reads or writes by allocations), unless force-destroy is requested and volSafeToForce confirms all its allocations are terminal. The deregistration transaction is aborted with this error so claimed volumes cannot be silently deleted.

Source

Thrown at nomad/state/state_store.go:2969

			return fmt.Errorf("volume lookup failed: %s: %v", id, err)
		}

		if existing == nil {
			return fmt.Errorf("volume not found: %s", id)
		}

		vol, ok := existing.(*structs.CSIVolume)
		if !ok {
			return fmt.Errorf("volume row conversion error: %s", id)
		}

		// The common case for a volume deregister is when the volume is
		// unused, but we can also let an operator intervene in the case where
		// allocations have been stopped but claims can't be freed because
		// ex. the plugins have all been removed.
		if vol.InUse() {
			if !force || !s.volSafeToForce(txn, vol) {
				return fmt.Errorf("volume in use: %s", id)
			}
		}

		if err = txn.Delete(TableCSIVolumes, existing); err != nil {
			return fmt.Errorf("volume delete failed: %s: %v", id, err)
		}
	}

	if err := txn.Insert("index", &IndexEntry{TableCSIVolumes, index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}

	return txn.Commit()
}

// volSafeToForce checks if the any of the remaining allocations
// are in a non-terminal state.
func (s *StateStore) volSafeToForce(txn Txn, v *structs.CSIVolume) bool {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Stop the jobs that mount the volume (nomad job stop) and wait for allocations to become terminal
  2. Retry deregistration once claims are released; check claim holders with `nomad volume status <id>`
  3. Use `nomad volume deregister -force <id>` (or --force-destroy in newer versions) only when allocations are gone but claims are stuck (e.g. plugins removed)
  4. If claims are permanently leaked due to missing plugins, force-deregister and clean up CSI plugin jobs

Example fix

# before
nomad volume deregister db-volume
# Error: volume in use
# after: stop the job first, then force if claims are stuck
nomad job stop -purge db-job
nomad volume deregister -force db-volume
Defensive patterns

Strategy: validation

Validate before calling

// Check for active claims and stop holders before deregistering
vol, _, err := client.CSIVolumes().Get(volumeID, nil)
if err != nil { return err }
if vol.InUse() {
	return fmt.Errorf("volume %s still in use; stop jobs first", volumeID)
}

Type guard

func volumeSafeToDelete(v *api.CSIVolume) bool {
	return v != nil && !v.InUse()
}

Try / catch

if err := deregisterVolume(volID); err != nil && strings.Contains(err.Error(), "volume in use") {
	// stop claiming jobs or retry with -force after confirming terminal allocs
}

Prevention

When it happens

Trigger: `nomad volume deregister` (without -force/--force-destroy) while allocations still hold read or write claims on the volume; or with force when claims belong to non-terminal allocations, failing volSafeToForce.

Common situations: Operators decommissioning storage while jobs still mount it; leaked claims from dead allocations (plugin removed before claims freed); retrying deregister before the job stopped.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/cea520801a788e9e. Report an issue: GitHub.