hashicorp/nomad · error

CSI.NodeDetachVolume: AllocID is required

Error message

CSI.NodeDetachVolume: AllocID is required

What it means

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.

Source

Thrown at client/csi_endpoint.go:513

	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,
	}

	err = manager.UnmountVolume(ctx, req.VolumeNamespace, req.VolumeID, req.ExternalID, req.AllocID, usageOpts)
	if err != nil && !errors.Is(err, nstructs.ErrCSIClientRPCIgnorable) {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set req.AllocID to the allocation's ID before calling
  2. 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
  3. Check GC ordering — volume unmount should complete before the alloc record is purged

Example fix

// before
req := &structs.NodeDetachVolumeRequest{PluginID: pluginID, VolumeID: volID}
// after
if allocID == "" { return fmt.Errorf("cannot detach volume %s: alloc already GC'd", volID) }
req := &structs.NodeDetachVolumeRequest{PluginID: pluginID, VolumeID: volID, AllocID: allocID}
Defensive patterns

Strategy: validation

Validate before calling

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

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(), "AllocID is required") {
        return fmt.Errorf("alloc already GC'd before detach of volume %s", req.VolumeID)
    }
    return err
}

Prevention

When it happens

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

Common situations: Allocation GC racing volume unmount; recovering mounts after client restart without the alloc context; manual RPC construction.

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