hashicorp/nomad · error
no such volume
Error message
no such volume
What it means
CSIVolume.Unpublish cannot find the requested volume in the state store and returns the terse "no such volume". Unlike volAndPluginLookup this path doesn't echo the ID, but the cause is the same: no CSIVolume exists under (args.Namespace, args.VolumeID) at the time of the RPC. The unpublish is aborted without touching claims or the controller.
Source
Thrown at nomad/csi_endpoint.go:723
if err := v.authorizeUnpublish(aclObj, args, allowVolume); err != nil {
return err
}
if args.VolumeID == "" {
return fmt.Errorf("missing volume ID")
}
if args.Claim == nil {
return fmt.Errorf("missing volume claim")
}
ws := memdb.NewWatchSet()
state := v.srv.fsm.State()
vol, err := state.CSIVolumeByID(ws, args.Namespace, args.VolumeID)
if err != nil {
return err
}
if vol == nil {
return fmt.Errorf("no such volume")
}
claim := args.Claim
// we need to checkpoint when we first get the claim to ensure we've set the
// initial "past claim" state, otherwise a client that unpublishes (skipping
// the node unpublish b/c it's done that work) fail to get written if the
// controller unpublish fails.
vol = vol.Copy()
err = v.checkpointClaim(vol, claim)
if err != nil {
return err
}
// previous checkpoints may have set the past claim state already.
// in practice we should never see CSIVolumeClaimStateControllerDetached
// but having an option for the state makes it easy to add a checkpoint
// in a backwards compatible way if we need one laterView on GitHub (pinned to 482b49bf1a)
Solutions
- Verify with `nomad volume status -namespace <ns> <vol-id>`; if already gone, treat the unpublish as a no-op in your cleanup logic.
- Re-register the volume if it must remain, then retry the unpublish.
- Confirm the request's namespace matches the volume's registered namespace.
- Serialize cleanup so volume delete only runs after all unpublish RPCs complete.
Example fix
// before: unconditional unpublish in cleanup
client.CSIVolumes().Unpublish(volID, ns, opts, req)
// after: tolerate already-deregistered volumes
err := client.CSIVolumes().Unpublish(volID, ns, opts, req)
if err != nil && strings.Contains(err.Error(), "no such volume") {
return nil // already gone; safe to skip
} Defensive patterns
Strategy: fallback
Validate before calling
vol, _, err := client.CSIVolumes().Info(volID, nil)
if err != nil || vol == nil {
return nil // volume already deregistered; nothing to unpublish
} Try / catch
if err != nil && strings.Contains(err.Error(), "no such volume") {
return nil // idempotent success: already deregistered
} Prevention
- Make cleanup scripts idempotent — treat 'no such volume' as success.
- Order teardown: unpublish all claims first, delete volume registration last.
- Verify the namespace matches the volume's registration.
When it happens
Trigger: Raised when state.CSIVolumeByID(ws, args.Namespace, args.VolumeID) returns nil in Unpublish: the volume was already deregistered/deleted, never existed, is in another namespace, or was deregistered concurrently between claim release and unpublish.
Common situations: Idempotent cleanup scripts unpublishing volumes that were already deregistered; raciness where `nomad volume delete` ran while a client was still unpublishing; namespace mismatch (caller authorized for a different namespace than the volume's).
Related errors
- volume not found: %s
- volume not found: %s
- missing policy name
- volume clone ID cannot be updated
- volume snapshot ID cannot be updated
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/ddd8a885de145966.
Report an issue: GitHub.