{"record":{"id":"c04af1aa12739cd9","repo":"hashicorp/nomad","slug":"csi-nodedetachvolume-allocid-is-required","errorCode":null,"errorMessage":"CSI.NodeDetachVolume: AllocID is required","messagePattern":"CSI\\.NodeDetachVolume: AllocID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/csi_endpoint.go","lineNumber":513,"sourceCode":"\treturn nil\n}\n\n// NodeDetachVolume is used to detach a volume from a CSI Cluster from\n// the storage node provided in the request.\nfunc (c *CSI) NodeDetachVolume(req *structs.ClientCSINodeDetachVolumeRequest, resp *structs.ClientCSINodeDetachVolumeResponse) error {\n\tdefer metrics.MeasureSince([]string{\"client\", \"csi_node\", \"detach_volume\"}, time.Now())\n\n\t// The following block of validation checks should not be reached on a\n\t// real Nomad cluster. They serve as a defensive check before forwarding\n\t// requests to plugins, and to aid with development.\n\tif req.PluginID == \"\" {\n\t\treturn errors.New(\"CSI.NodeDetachVolume: PluginID is required\")\n\t}\n\tif req.VolumeID == \"\" {\n\t\treturn errors.New(\"CSI.NodeDetachVolume: VolumeID is required\")\n\t}\n\tif req.AllocID == \"\" {\n\t\treturn errors.New(\"CSI.NodeDetachVolume: AllocID is required\")\n\t}\n\n\tctx, cancelFn := c.requestContext()\n\tdefer cancelFn()\n\n\tmanager, err := c.c.csimanager.ManagerForPlugin(ctx, req.PluginID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"CSI.NodeDetachVolume: %v\", err)\n\t}\n\n\tusageOpts := &csimanager.UsageOptions{\n\t\tReadOnly:       req.ReadOnly,\n\t\tAttachmentMode: req.AttachmentMode,\n\t\tAccessMode:     req.AccessMode,\n\t}\n\n\terr = manager.UnmountVolume(ctx, req.VolumeNamespace, req.VolumeID, req.ExternalID, req.AllocID, usageOpts)\n\tif err != nil && !errors.Is(err, nstructs.ErrCSIClientRPCIgnorable) {","sourceCodeStart":495,"sourceCodeEnd":531,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/csi_endpoint.go#L495-L531","documentation":"NodeDetachVolume requires the AllocID of the allocation releasing the volume, so the plugin manager can locate the per-allocation volume usage record (mount point, staging target) to detach. An empty AllocID returns this defensive error.","triggerScenarios":"Calling NodeDetachVolume without req.AllocID — e.g. detaching after the allocation was already GC'd so its ID wasn't carried into the request, or hand-built requests in tests.","commonSituations":"Allocation GC racing volume unmount; recovering mounts after client restart without the alloc context; manual RPC construction.","solutions":["Set req.AllocID to the allocation's ID before calling","If the alloc is gone, use the recover/deregister path rather than a bare detach, or stop the alloc to trigger unmount with proper context","Check GC ordering — volume unmount should complete before the alloc record is purged"],"exampleFix":"// before\nreq := &structs.NodeDetachVolumeRequest{PluginID: pluginID, VolumeID: volID}\n// after\nif allocID == \"\" { return fmt.Errorf(\"cannot detach volume %s: alloc already GC'd\", volID) }\nreq := &structs.NodeDetachVolumeRequest{PluginID: pluginID, VolumeID: volID, AllocID: allocID}","handlingStrategy":"validation","validationCode":"if req == nil || req.AllocID == \"\" {\n    return errors.New(\"NodeDetachVolume requires a non-empty AllocID\")\n}","typeGuard":"func detachNodeReady(req *structs.NodeDetachVolumeRequest) bool {\n    return req != nil && req.PluginID != \"\" && req.VolumeID != \"\" && req.AllocID != \"\"\n}","tryCatchPattern":"if err := client.NodeDetachVolume(req, &resp); err != nil {\n    if strings.Contains(err.Error(), \"AllocID is required\") {\n        return fmt.Errorf(\"alloc already GC'd before detach of volume %s\", req.VolumeID)\n    }\n    return err\n}","preventionTips":["Perform node detach while the allocation record still exists — before GC","Keep alloc ID in the volume-usage record used by unmount paths","Ensure the unmount hook runs before allocation terminal cleanup completes"],"tags":["csi","validation","nomad","storage"],"backgroundTag":"missing-required-argument","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"}