{"record":{"id":"81a8dcdd320e78a6","repo":"hashicorp/nomad","slug":"csi-controllerattachvolume-clientcsinodeid-is-req","errorCode":null,"errorMessage":"CSI.ControllerAttachVolume: ClientCSINodeID is required","messagePattern":"CSI\\.ControllerAttachVolume: ClientCSINodeID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/csi_endpoint.go","lineNumber":111,"sourceCode":"\tif err != nil {\n\t\t// the server's view of the plugin health is stale, so let it know it\n\t\t// should retry with another controller instance\n\t\treturn fmt.Errorf(\"CSI.ControllerAttachVolume: %w: %v\",\n\t\t\tnstructs.ErrCSIClientRPCRetryable, err)\n\t}\n\tdefer plugin.Close()\n\n\t// The following block of validation checks should not be reached on a\n\t// real Nomad cluster as all of this data should be validated when registering\n\t// volumes with the cluster. They serve as a defensive check before forwarding\n\t// requests to plugins, and to aid with development.\n\n\tif req.VolumeID == \"\" {\n\t\treturn errors.New(\"CSI.ControllerAttachVolume: VolumeID is required\")\n\t}\n\n\tif req.ClientCSINodeID == \"\" {\n\t\treturn errors.New(\"CSI.ControllerAttachVolume: ClientCSINodeID is required\")\n\t}\n\n\tcsiReq, err := req.ToCSIRequest()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"CSI.ControllerAttachVolume: %v\", err)\n\t}\n\n\t// Submit the request for a volume to the CSI Plugin.\n\tctx, cancelFn := c.requestContext()\n\tdefer cancelFn()\n\t// CSI ControllerPublishVolume errors for timeout, codes.Unavailable and\n\t// codes.ResourceExhausted are retried; all other errors are fatal.\n\tcresp, err := plugin.ControllerPublishVolume(ctx, csiReq,\n\t\tgrpc_retry.WithPerRetryTimeout(CSIPluginRequestTimeout),\n\t\tgrpc_retry.WithMax(3),\n\t\tgrpc_retry.WithBackoff(grpc_retry.BackoffExponential(100*time.Millisecond)))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"CSI.ControllerAttachVolume: %v\", err)","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/csi_endpoint.go#L93-L129","documentation":"In the same ControllerAttachVolume validation block, the RPC requires ClientCSINodeID — the ID of the CSI node plugin on the target client — so the controller plugin knows which node the volume is being attached to. An empty value returns this defensive error before any plugin call is made.","triggerScenarios":"Calling ControllerAttachVolume with a request built without ClientCSINodeID, typically when the node's CSI node plugin ID was never fingerprinted/registered or the caller passed the Nomad node ID instead of the CSI plugin node ID.","commonSituations":"Node plugin not yet registered in the dynamic plugin registry when attach is attempted; passing nomadNode.ID instead of the plugin's node ID; manual RPC construction in tests.","solutions":["Set ClientCSINodeID from the node's registered CSI node plugin (csimanager / NodeInfo CSINodeID)","Wait for the node plugin to register before issuing attach; check node.CSINodeAttributes/plugins fingerprinting","Verify you are not confusing the Nomad node ID with the CSI node ID"],"exampleFix":"// before\nreq := &structs.ControllerAttachVolumeRequest{VolumeID: volID}\n// after\nreq := &structs.ControllerAttachVolumeRequest{VolumeID: volID, ClientCSINodeID: node.CSINodeID}\nif node.CSINodeID == \"\" { return errors.New(\"node CSI plugin not yet fingerprinted\") }","handlingStrategy":"validation","validationCode":"if req.ClientCSINodeID == \"\" {\n    return errors.New(\"ControllerAttachVolume requires ClientCSINodeID; wait for node CSI plugin fingerprint\")\n}","typeGuard":"func hasCSINodeID(n *structs.Node) bool { return n != nil && n.CSINodeID != \"\" }","tryCatchPattern":"if err := client.ControllerAttachVolume(req, &resp); err != nil {\n    if strings.Contains(err.Error(), \"ClientCSINodeID is required\") {\n        return errors.New(\"node CSI plugin not registered yet; retry after fingerprinting\")\n    }\n    return err\n}","preventionTips":["Verify node.CSINodeID is populated before scheduling/attach","Confirm the CSI node plugin is in the node's registered plugin list","Don't confuse the Nomad node ID with the CSI node ID"],"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"}