hashicorp/nomad · error
CSI.ControllerDetachVolume: ClientCSINodeID is required
Error message
CSI.ControllerDetachVolume: ClientCSINodeID is required
What it means
ControllerDetachVolume also requires ClientCSINodeID so the controller plugin can identify which node to detach the volume from. An empty value returns this defensive error before the plugin is contacted.
Source
Thrown at client/csi_endpoint.go:159
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.ControllerDetachVolume: %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.ControllerDetachVolume: VolumeID is required")
}
if req.ClientCSINodeID == "" {
return errors.New("CSI.ControllerDetachVolume: ClientCSINodeID is required")
}
csiReq := req.ToCSIRequest()
// Submit the request for a volume to the CSI Plugin.
ctx, cancelFn := c.requestContext()
defer cancelFn()
// CSI ControllerUnpublishVolume errors for timeout, codes.Unavailable and
// codes.ResourceExhausted are retried; all other errors are fatal.
_, err = plugin.ControllerUnpublishVolume(ctx, csiReq,
grpc_retry.WithPerRetryTimeout(CSIPluginRequestTimeout),
grpc_retry.WithMax(3),
grpc_retry.WithBackoff(grpc_retry.BackoffExponential(100*time.Millisecond)))
if errors.Is(err, nstructs.ErrCSIClientRPCIgnorable) {
// if the controller detach previously happened but the server failed to
// checkpoint, we'll get an error from the plugin but can safely ignore it.
c.c.logger.Debug("could not unpublish volume", "error", err)
return nilView on GitHub (pinned to 482b49bf1a)
Solutions
- Populate ClientCSINodeID with the node's CSI node plugin ID
- If the node is gone, treat the detach as best-effort and rely on the controller's unpublish/timeout instead of a per-node detach
- Wait for node re-registration if the plugin is temporarily missing
Example fix
// before
req := &structs.ControllerDetachVolumeRequest{VolumeID: volID, ExternalID: extID}
// after
if node.CSINodeID == "" { return errors.New("cannot detach: node CSI plugin ID unknown") }
req := &structs.ControllerDetachVolumeRequest{VolumeID: volID, ClientCSINodeID: node.CSINodeID, ExternalID: extID} Defensive patterns
Strategy: validation
Validate before calling
if req.ClientCSINodeID == "" {
return errors.New("ControllerDetachVolume requires ClientCSINodeID")
} Type guard
func hasCSINodeID(n *structs.Node) bool { return n != nil && n.CSINodeID != "" } Try / catch
if err := client.ControllerDetachVolume(req, &resp); err != nil {
if strings.Contains(err.Error(), "ClientCSINodeID is required") {
return errors.New("node gone or plugin unregistered; relying on controller unpublish timeout")
}
return err
} Prevention
- Capture node.CSINodeID at claim time so detach has it even if the node leaves
- Handle node-deregistration by deferring to the controller's unpublish capability
- Add unit tests for detach with partially filled requests
When it happens
Trigger: Calling ControllerDetachVolume without ClientCSINodeID — typically when the node plugin ID was never resolved, or the request was hand-built without it.
Common situations: Node deregistered or its CSI plugin uninstalled before detach; manual RPC construction; passing the wrong identifier field.
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
- CSI.ControllerAttachVolume: VolumeID is required
- CSI.ControllerAttachVolume: ClientCSINodeID is required
- CSI.ControllerDetachVolume: VolumeID is required
- CSI.NodeDetachVolume: PluginID is required
- CSI.NodeDetachVolume: VolumeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f1b6aaaee1d8fbe7.
Report an issue: GitHub.