hashicorp/nomad · error

CSI.NodeDetachVolume: VolumeID is required

Error message

CSI.NodeDetachVolume: VolumeID is required

What it means

NodeDetachVolume requires the VolumeID so the plugin manager can find the volume usage / detach the right volume on the node. An empty VolumeID returns this defensive error before contacting the plugin.

Source

Thrown at client/csi_endpoint.go:510

		}
	}

	return nil
}

// NodeDetachVolume is used to detach a volume from a CSI Cluster from
// the storage node provided in the request.
func (c *CSI) NodeDetachVolume(req *structs.ClientCSINodeDetachVolumeRequest, resp *structs.ClientCSINodeDetachVolumeResponse) error {
	defer metrics.MeasureSince([]string{"client", "csi_node", "detach_volume"}, time.Now())

	// The following block of validation checks should not be reached on a
	// real Nomad cluster. They serve as a defensive check before forwarding
	// requests to plugins, and to aid with development.
	if req.PluginID == "" {
		return errors.New("CSI.NodeDetachVolume: PluginID is required")
	}
	if req.VolumeID == "" {
		return errors.New("CSI.NodeDetachVolume: VolumeID is required")
	}
	if req.AllocID == "" {
		return errors.New("CSI.NodeDetachVolume: AllocID is required")
	}

	ctx, cancelFn := c.requestContext()
	defer cancelFn()

	manager, err := c.c.csimanager.ManagerForPlugin(ctx, req.PluginID)
	if err != nil {
		return fmt.Errorf("CSI.NodeDetachVolume: %v", err)
	}

	usageOpts := &csimanager.UsageOptions{
		ReadOnly:       req.ReadOnly,
		AttachmentMode: req.AttachmentMode,
		AccessMode:     req.AccessMode,
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set req.VolumeID from the allocation's volume claim (alloc.AllocatedResources.VolumeClaims[].VolumeID)
  2. Skip the detach when no claim exists (nothing was mounted)
  3. Check for races between claim GC and detach

Example fix

// before
req := &structs.NodeDetachVolumeRequest{PluginID: pluginID, AllocID: allocID}
// after
if claim.VolumeID == "" { return nil }
req := &structs.NodeDetachVolumeRequest{PluginID: pluginID, VolumeID: claim.VolumeID, AllocID: allocID}
Defensive patterns

Strategy: validation

Validate before calling

if req == nil || req.VolumeID == "" {
    return errors.New("NodeDetachVolume requires a non-empty VolumeID")
}

Type guard

func detachNodeReady(req *structs.NodeDetachVolumeRequest) bool {
    return req != nil && req.PluginID != "" && req.VolumeID != "" && req.AllocID != ""
}

Try / catch

if err := client.NodeDetachVolume(req, &resp); err != nil {
    if strings.Contains(err.Error(), "VolumeID is required") {
        return nil // no claim to detach
    }
    return err
}

Prevention

When it happens

Trigger: Calling NodeDetachVolume with req.VolumeID == "" — e.g. when the claim's volume ID was lost or the caller only had the allocation and forgot to resolve the volume.

Common situations: Unmount paths iterating allocations without carrying the volume ID; volume deregistered concurrently; manual test RPCs.

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/5282b838aba89601. Report an issue: GitHub.