hashicorp/nomad · error

CSI.ControllerAttachVolume: ClientCSINodeID is required

Error message

CSI.ControllerAttachVolume: ClientCSINodeID is required

What it means

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.

Source

Thrown at client/csi_endpoint.go:111

	if err != nil {
		// the server's view of the plugin health is stale, so let it know it
		// should retry with another controller instance
		return fmt.Errorf("CSI.ControllerAttachVolume: %w: %v",
			nstructs.ErrCSIClientRPCRetryable, err)
	}
	defer plugin.Close()

	// The following block of validation checks should not be reached on a
	// real Nomad cluster as all of this data should be validated when registering
	// volumes with the cluster. They serve as a defensive check before forwarding
	// requests to plugins, and to aid with development.

	if req.VolumeID == "" {
		return errors.New("CSI.ControllerAttachVolume: VolumeID is required")
	}

	if req.ClientCSINodeID == "" {
		return errors.New("CSI.ControllerAttachVolume: ClientCSINodeID is required")
	}

	csiReq, err := req.ToCSIRequest()
	if err != nil {
		return fmt.Errorf("CSI.ControllerAttachVolume: %v", err)
	}

	// Submit the request for a volume to the CSI Plugin.
	ctx, cancelFn := c.requestContext()
	defer cancelFn()
	// CSI ControllerPublishVolume errors for timeout, codes.Unavailable and
	// codes.ResourceExhausted are retried; all other errors are fatal.
	cresp, err := plugin.ControllerPublishVolume(ctx, csiReq,
		grpc_retry.WithPerRetryTimeout(CSIPluginRequestTimeout),
		grpc_retry.WithMax(3),
		grpc_retry.WithBackoff(grpc_retry.BackoffExponential(100*time.Millisecond)))
	if err != nil {
		return fmt.Errorf("CSI.ControllerAttachVolume: %v", err)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set ClientCSINodeID from the node's registered CSI node plugin (csimanager / NodeInfo CSINodeID)
  2. Wait for the node plugin to register before issuing attach; check node.CSINodeAttributes/plugins fingerprinting
  3. Verify you are not confusing the Nomad node ID with the CSI node ID

Example fix

// before
req := &structs.ControllerAttachVolumeRequest{VolumeID: volID}
// after
req := &structs.ControllerAttachVolumeRequest{VolumeID: volID, ClientCSINodeID: node.CSINodeID}
if node.CSINodeID == "" { return errors.New("node CSI plugin not yet fingerprinted") }
Defensive patterns

Strategy: validation

Validate before calling

if req.ClientCSINodeID == "" {
    return errors.New("ControllerAttachVolume requires ClientCSINodeID; wait for node CSI plugin fingerprint")
}

Type guard

func hasCSINodeID(n *structs.Node) bool { return n != nil && n.CSINodeID != "" }

Try / catch

if err := client.ControllerAttachVolume(req, &resp); err != nil {
    if strings.Contains(err.Error(), "ClientCSINodeID is required") {
        return errors.New("node CSI plugin not registered yet; retry after fingerprinting")
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/81a8dcdd320e78a6. Report an issue: GitHub.