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
- Stop the jobs that mount the volume (nomad job stop) and wait for allocations to become terminal
- Retry deregistration once claims are released; check claim holders with `nomad volume status <id>`
- 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)
- 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
- Stop mounting jobs and wait for terminal allocs before deregistering
- Inspect claims via nomad volume status <id>
- Use -force only for leaked claims (e.g. removed plugins)
- Automate claim release in decommission runbooks
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
- error parsing: root should be an object
- missing policy name
- cannot specify Accessor ID
- missing accessor ID
- missing secret ID
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/cea520801a788e9e.
Report an issue: GitHub.