{"record":{"id":"ddd8a885de145966","repo":"hashicorp/nomad","slug":"no-such-volume","errorCode":null,"errorMessage":"no such volume","messagePattern":"no such volume","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/csi_endpoint.go","lineNumber":723,"sourceCode":"\tif err := v.authorizeUnpublish(aclObj, args, allowVolume); err != nil {\n\t\treturn err\n\t}\n\n\tif args.VolumeID == \"\" {\n\t\treturn fmt.Errorf(\"missing volume ID\")\n\t}\n\tif args.Claim == nil {\n\t\treturn fmt.Errorf(\"missing volume claim\")\n\t}\n\n\tws := memdb.NewWatchSet()\n\tstate := v.srv.fsm.State()\n\tvol, err := state.CSIVolumeByID(ws, args.Namespace, args.VolumeID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif vol == nil {\n\t\treturn fmt.Errorf(\"no such volume\")\n\t}\n\n\tclaim := args.Claim\n\n\t// we need to checkpoint when we first get the claim to ensure we've set the\n\t// initial \"past claim\" state, otherwise a client that unpublishes (skipping\n\t// the node unpublish b/c it's done that work) fail to get written if the\n\t// controller unpublish fails.\n\tvol = vol.Copy()\n\terr = v.checkpointClaim(vol, claim)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// previous checkpoints may have set the past claim state already.\n\t// in practice we should never see CSIVolumeClaimStateControllerDetached\n\t// but having an option for the state makes it easy to add a checkpoint\n\t// in a backwards compatible way if we need one later","sourceCodeStart":705,"sourceCodeEnd":741,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/csi_endpoint.go#L705-L741","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before: unconditional unpublish in cleanup\nclient.CSIVolumes().Unpublish(volID, ns, opts, req)\n// after: tolerate already-deregistered volumes\nerr := client.CSIVolumes().Unpublish(volID, ns, opts, req)\nif err != nil && strings.Contains(err.Error(), \"no such volume\") {\n    return nil // already gone; safe to skip\n}","handlingStrategy":"fallback","validationCode":"vol, _, err := client.CSIVolumes().Info(volID, nil)\nif err != nil || vol == nil {\n    return nil // volume already deregistered; nothing to unpublish\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no such volume\") {\n    return nil // idempotent success: already deregistered\n}","preventionTips":["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."],"tags":["nomad","csi","volume","not-found","unpublish"],"backgroundTag":"volume-not-found","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}