{"record":{"id":"a82977e4c24c04c6","repo":"hashicorp/nomad","slug":"plugin-q-for-volume-q-not-found","errorCode":null,"errorMessage":"plugin %q for volume %q not found","messagePattern":"plugin %q for volume %q not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/csi_endpoint.go","lineNumber":1472,"sourceCode":"\t}\n\n\tif len(args.VolumeIDs) == 0 {\n\t\treturn fmt.Errorf(\"missing volume IDs\")\n\t}\n\n\tfor _, volID := range args.VolumeIDs {\n\n\t\tplugin, vol, err := v.volAndPluginLookup(args.Namespace, volID)\n\t\tif err != nil {\n\t\t\tif err == fmt.Errorf(\"volume not found: %s\", volID) {\n\t\t\t\tv.logger.Warn(\"volume %q to be deleted was already deregistered\")\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif plugin == nil {\n\t\t\treturn fmt.Errorf(\"plugin %q for volume %q not found\", vol.PluginID, volID)\n\t\t}\n\n\t\t// NOTE: deleting the volume in the external storage provider can't be\n\t\t// made atomic with deregistration. We can't delete a volume that's\n\t\t// not registered because we need to be able to lookup its plugin.\n\t\terr = v.deleteVolume(vol, plugin, args.Secrets)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tderegArgs := &structs.CSIVolumeDeregisterRequest{\n\t\tVolumeIDs:    args.VolumeIDs,\n\t\tWriteRequest: args.WriteRequest,\n\t}\n\t_, index, err := v.srv.raftApply(structs.CSIVolumeDeregisterRequestType, deregArgs)\n\tif err != nil {\n\t\tv.logger.Error(\"csi raft apply failed\", \"error\", err, \"method\", \"deregister\")","sourceCodeStart":1454,"sourceCodeEnd":1490,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/csi_endpoint.go#L1454-L1490","documentation":"Returned by CSIVolumeEndpoint.Delete when the volume record exists but its referenced CSI plugin (vol.PluginID) is no longer registered in the agent's plugin registry. Without the plugin handle Nomad cannot send the ControllerDeleteVolume RPC to the storage provider, so it refuses to delete rather than silently orphaning the backend volume.","triggerScenarios":"Calling `nomad volume delete` after the CSI plugin job was stopped/failed, the controller node was drained/removed, or the plugin deregistered due to health-check failure while the volume record still exists in state.","commonSituations":"Cleanup scripts run after tearing down the plugin deployment; plugin job crashed and Nomad GC'd its registration; upgrading/migrating storage drivers leaving stale volume registrations; wrong cluster (volume from a different cluster's plugin).","solutions":["Restore/redeploy the CSI plugin job (same plugin ID) so the controller is registered, then retry the volume delete.","Use `nomad plugin status` to confirm the plugin is healthy and `nomad volume status <id>` to confirm vol.PluginID matches the running plugin.","If the plugin is permanently gone, deregister the volume instead of deleting it, and delete the volume manually in the storage provider.","Prevent by deleting volumes before stopping the CSI plugin job in teardown runbooks."],"exampleFix":"# before: plugin already stopped, delete fails\nnomad volume delete web-data\n# after: re-run the csi plugin job first\nnomad job run csi-plugin.nomad && nomad volume delete web-data","handlingStrategy":"validation","validationCode":"v, _, err := client.CSIVolumes().Get(ns, id, nil)\nif err != nil { return err }\np, _, err := client.CSIPlugins().Get(v.PluginID, nil)\nif err != nil || p.ControllersHealthy == 0 {\n    return fmt.Errorf(\"plugin %s for volume %s is not registered/healthy; redeploy CSI plugin first\", v.PluginID, id)\n}","typeGuard":"func isPluginMissing(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"not found\") && strings.Contains(err.Error(), \"plugin\")\n}","tryCatchPattern":"err := client.CSIVolumes().Delete(ns, []string{id}, secrets)\nif err != nil && strings.Contains(err.Error(), \"plugin\") && strings.Contains(err.Error(), \"not found\") {\n    // redeploy the CSI plugin job, then retry the delete\n}","preventionTips":["Keep the CSI plugin job running until all volumes are deleted (teardown order: volumes first, plugin last).","Check `nomad plugin status` before any volume lifecycle operation.","Alert on CSI plugin job failures so volumes never outlive their controller.","Favor deregister over delete when a plugin is permanently gone; clean the backend manually."],"tags":["csi","plugin","storage","lifecycle"],"backgroundTag":"csi-plugin-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"}